<?xml version="1.0" encoding="UTF-8"?>
<rss version="2.0" xmlns:atom="http://www.w3.org/2005/Atom" xmlns:dc="http://purl.org/dc/elements/1.1/">
  <channel>
    <title>Forem: Frank Kumro</title>
    <description>The latest articles on Forem by Frank Kumro (@frigidcode).</description>
    <link>https://forem.com/frigidcode</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%2F92806%2F43c9cc8a-07b7-4854-b559-706d64ce3a36.jpg</url>
      <title>Forem: Frank Kumro</title>
      <link>https://forem.com/frigidcode</link>
    </image>
    <atom:link rel="self" type="application/rss+xml" href="https://forem.com/feed/frigidcode"/>
    <language>en</language>
    <item>
      <title>Deploy Elixir apps utilizing Rust NIFs on Render.com</title>
      <dc:creator>Frank Kumro</dc:creator>
      <pubDate>Wed, 19 Feb 2020 23:11:04 +0000</pubDate>
      <link>https://forem.com/frigidcode/deploy-elixir-apps-utilizing-rust-nifs-on-render-com-1c7l</link>
      <guid>https://forem.com/frigidcode/deploy-elixir-apps-utilizing-rust-nifs-on-render-com-1c7l</guid>
      <description>&lt;p&gt;&lt;a href="https://res.cloudinary.com/practicaldev/image/fetch/s--lG7paAkG--/c_limit%2Cf_auto%2Cfl_progressive%2Cq_auto%2Cw_880/https://frank.kumro.io/content/images/2020/02/render.png" class="article-body-image-wrapper"&gt;&lt;img src="https://res.cloudinary.com/practicaldev/image/fetch/s--lG7paAkG--/c_limit%2Cf_auto%2Cfl_progressive%2Cq_auto%2Cw_880/https://frank.kumro.io/content/images/2020/02/render.png" alt="Deploy Elixir apps utilizing Rust NIFs on Render.com"&gt;&lt;/a&gt;&lt;/p&gt;

&lt;p&gt;After a long week of dealing with servers at my day job I had no urge to do the same with my side projects. I looked at Render.com and decided to try them out. All was well until I decided to add a mix package that built a Rust NIF. The default build container used by Render for Elixir projects didn't include Rust but after chatting with their team on Slack I came up with a solution, Docker.&lt;/p&gt;

&lt;p&gt;The first step is to determine what containers would have the functionality I needed. Then they would be combined using a multi-stage Docker build resulting in a container that could build Elixir projects with Rust NIFs. This was as easy as copying and pasting from the official Elixir and Rust Dockerfiles with very minor modifications.&lt;/p&gt;

&lt;p&gt;TLDR; linking to the complete Dockerfile at bottom of article.&lt;/p&gt;

&lt;h2&gt;
  
  
  Erlang
&lt;/h2&gt;

&lt;p&gt;The starting point for all the containers would be Erlang, 22-slim to be precise. It's important to determine what base container the Erlang 22-slim container is using as it will need to be the same for each additional container.&lt;/p&gt;

&lt;p&gt;Erlang uses &lt;code&gt;debian:buster&lt;/code&gt; per the Erlang &lt;a href="https://github.com/erlang/docker-erlang-otp/blob/636231974186645b6c96c6c888e61fd086394c3a/22/slim/Dockerfile"&gt;Dockerfile&lt;/a&gt;. Thus all our other containers must also be derived from &lt;code&gt;debian:buster&lt;/code&gt;.&lt;/p&gt;

&lt;p&gt;The first line of our &lt;code&gt;Dockerfile&lt;/code&gt; will be specifying the container to use for the first stage, building Rust. Using the &lt;code&gt;AS&lt;/code&gt; instruction allows future steps to utilize the container built in this step by name.&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight"&gt;&lt;pre class="highlight docker"&gt;&lt;code&gt;&lt;span class="k"&gt;FROM&lt;/span&gt;&lt;span class="s"&gt; erlang:22-slim AS rust_builder&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;



&lt;h2&gt;
  
  
  Rust
&lt;/h2&gt;

&lt;p&gt;The contents of the official Rust &lt;code&gt;Dockerfile&lt;/code&gt; can be copied into the &lt;code&gt;rust_builder&lt;/code&gt; step as long as the Rust container uses &lt;code&gt;buster&lt;/code&gt;.&lt;/p&gt;

&lt;p&gt;&lt;a href="https://res.cloudinary.com/practicaldev/image/fetch/s--43yByqOQ--/c_limit%2Cf_auto%2Cfl_progressive%2Cq_auto%2Cw_880/https://github.com/rust-lang/docker-rust" class="article-body-image-wrapper"&gt;&lt;img src="https://res.cloudinary.com/practicaldev/image/fetch/s--43yByqOQ--/c_limit%2Cf_auto%2Cfl_progressive%2Cq_auto%2Cw_880/https://github.com/rust-lang/docker-rust" alt="rust-lang/docker-rust"&gt;&lt;/a&gt;&lt;/p&gt;

&lt;p&gt;Our &lt;code&gt;Dockerfile&lt;/code&gt; for Rust is shown below:&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight"&gt;&lt;pre class="highlight docker"&gt;&lt;code&gt;&lt;span class="k"&gt;FROM&lt;/span&gt;&lt;span class="s"&gt; erlang:22-slim as rust_builder&lt;/span&gt;

&lt;span class="k"&gt;ENV&lt;/span&gt;&lt;span class="s"&gt; RUSTUP_HOME=/usr/local/rustup \&lt;/span&gt;
    CARGO_HOME=/usr/local/cargo \
    PATH=/usr/local/cargo/bin:$PATH \
    RUST_VERSION=1.41.0

&lt;span class="k"&gt;RUN &lt;/span&gt;&lt;span class="nb"&gt;set&lt;/span&gt; &lt;span class="nt"&gt;-eux&lt;/span&gt;&lt;span class="p"&gt;;&lt;/span&gt; &lt;span class="se"&gt;\
&lt;/span&gt;    apt-get update&lt;span class="p"&gt;;&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;-y&lt;/span&gt; &lt;span class="nt"&gt;--no-install-recommends&lt;/span&gt; &lt;span class="se"&gt;\
&lt;/span&gt;        ca-certificates &lt;span class="se"&gt;\
&lt;/span&gt;        gcc &lt;span class="se"&gt;\
&lt;/span&gt;        libc6-dev &lt;span class="se"&gt;\
&lt;/span&gt;        wget &lt;span class="se"&gt;\
&lt;/span&gt;        &lt;span class="p"&gt;;&lt;/span&gt; &lt;span class="se"&gt;\
&lt;/span&gt;    &lt;span class="nv"&gt;dpkgArch&lt;/span&gt;&lt;span class="o"&gt;=&lt;/span&gt;&lt;span class="s2"&gt;"&lt;/span&gt;&lt;span class="si"&gt;$(&lt;/span&gt;dpkg &lt;span class="nt"&gt;--print-architecture&lt;/span&gt;&lt;span class="si"&gt;)&lt;/span&gt;&lt;span class="s2"&gt;"&lt;/span&gt;&lt;span class="p"&gt;;&lt;/span&gt; &lt;span class="se"&gt;\
&lt;/span&gt;    &lt;span class="k"&gt;case&lt;/span&gt; &lt;span class="s2"&gt;"&lt;/span&gt;&lt;span class="k"&gt;${&lt;/span&gt;&lt;span class="nv"&gt;dpkgArch&lt;/span&gt;&lt;span class="p"&gt;##*-&lt;/span&gt;&lt;span class="k"&gt;}&lt;/span&gt;&lt;span class="s2"&gt;"&lt;/span&gt; &lt;span class="k"&gt;in&lt;/span&gt; &lt;span class="se"&gt;\
&lt;/span&gt;        amd64&lt;span class="p"&gt;)&lt;/span&gt; &lt;span class="nv"&gt;rustArch&lt;/span&gt;&lt;span class="o"&gt;=&lt;/span&gt;&lt;span class="s1"&gt;'x86_64-unknown-linux-gnu'&lt;/span&gt;&lt;span class="p"&gt;;&lt;/span&gt; &lt;span class="nv"&gt;rustupSha256&lt;/span&gt;&lt;span class="o"&gt;=&lt;/span&gt;&lt;span class="s1"&gt;'ad1f8b5199b3b9e231472ed7aa08d2e5d1d539198a15c5b1e53c746aad81d27b'&lt;/span&gt; &lt;span class="p"&gt;;;&lt;/span&gt; &lt;span class="se"&gt;\
&lt;/span&gt;        armhf&lt;span class="p"&gt;)&lt;/span&gt; &lt;span class="nv"&gt;rustArch&lt;/span&gt;&lt;span class="o"&gt;=&lt;/span&gt;&lt;span class="s1"&gt;'armv7-unknown-linux-gnueabihf'&lt;/span&gt;&lt;span class="p"&gt;;&lt;/span&gt; &lt;span class="nv"&gt;rustupSha256&lt;/span&gt;&lt;span class="o"&gt;=&lt;/span&gt;&lt;span class="s1"&gt;'6c6c3789dabf12171c7f500e06d21d8004b5318a5083df8b0b02c0e5ef1d017b'&lt;/span&gt; &lt;span class="p"&gt;;;&lt;/span&gt; &lt;span class="se"&gt;\
&lt;/span&gt;        arm64&lt;span class="p"&gt;)&lt;/span&gt; &lt;span class="nv"&gt;rustArch&lt;/span&gt;&lt;span class="o"&gt;=&lt;/span&gt;&lt;span class="s1"&gt;'aarch64-unknown-linux-gnu'&lt;/span&gt;&lt;span class="p"&gt;;&lt;/span&gt; &lt;span class="nv"&gt;rustupSha256&lt;/span&gt;&lt;span class="o"&gt;=&lt;/span&gt;&lt;span class="s1"&gt;'26942c80234bac34b3c1352abbd9187d3e23b43dae3cf56a9f9c1ea8ee53076d'&lt;/span&gt; &lt;span class="p"&gt;;;&lt;/span&gt; &lt;span class="se"&gt;\
&lt;/span&gt;        i386&lt;span class="p"&gt;)&lt;/span&gt; &lt;span class="nv"&gt;rustArch&lt;/span&gt;&lt;span class="o"&gt;=&lt;/span&gt;&lt;span class="s1"&gt;'i686-unknown-linux-gnu'&lt;/span&gt;&lt;span class="p"&gt;;&lt;/span&gt; &lt;span class="nv"&gt;rustupSha256&lt;/span&gt;&lt;span class="o"&gt;=&lt;/span&gt;&lt;span class="s1"&gt;'27ae12bc294a34e566579deba3e066245d09b8871dc021ef45fc715dced05297'&lt;/span&gt; &lt;span class="p"&gt;;;&lt;/span&gt; &lt;span class="se"&gt;\
&lt;/span&gt;        &lt;span class="k"&gt;*&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt; &lt;span class="nb"&gt;echo&lt;/span&gt; &lt;span class="o"&gt;&amp;gt;&lt;/span&gt;&amp;amp;2 &lt;span class="s2"&gt;"unsupported architecture: &lt;/span&gt;&lt;span class="k"&gt;${&lt;/span&gt;&lt;span class="nv"&gt;dpkgArch&lt;/span&gt;&lt;span class="k"&gt;}&lt;/span&gt;&lt;span class="s2"&gt;"&lt;/span&gt;&lt;span class="p"&gt;;&lt;/span&gt; &lt;span class="nb"&gt;exit &lt;/span&gt;1 &lt;span class="p"&gt;;;&lt;/span&gt; &lt;span class="se"&gt;\
&lt;/span&gt;    &lt;span class="k"&gt;esac&lt;/span&gt;&lt;span class="p"&gt;;&lt;/span&gt; &lt;span class="se"&gt;\
&lt;/span&gt;    &lt;span class="nv"&gt;url&lt;/span&gt;&lt;span class="o"&gt;=&lt;/span&gt;&lt;span class="s2"&gt;"https://static.rust-lang.org/rustup/archive/1.21.1/&lt;/span&gt;&lt;span class="k"&gt;${&lt;/span&gt;&lt;span class="nv"&gt;rustArch&lt;/span&gt;&lt;span class="k"&gt;}&lt;/span&gt;&lt;span class="s2"&gt;/rustup-init"&lt;/span&gt;&lt;span class="p"&gt;;&lt;/span&gt; &lt;span class="se"&gt;\
&lt;/span&gt;    wget &lt;span class="s2"&gt;"&lt;/span&gt;&lt;span class="nv"&gt;$url&lt;/span&gt;&lt;span class="s2"&gt;"&lt;/span&gt;&lt;span class="p"&gt;;&lt;/span&gt; &lt;span class="se"&gt;\
&lt;/span&gt;    &lt;span class="nb"&gt;echo&lt;/span&gt; &lt;span class="s2"&gt;"&lt;/span&gt;&lt;span class="k"&gt;${&lt;/span&gt;&lt;span class="nv"&gt;rustupSha256&lt;/span&gt;&lt;span class="k"&gt;}&lt;/span&gt;&lt;span class="s2"&gt; *rustup-init"&lt;/span&gt; | &lt;span class="nb"&gt;sha256sum&lt;/span&gt; &lt;span class="nt"&gt;-c&lt;/span&gt; -&lt;span class="p"&gt;;&lt;/span&gt; &lt;span class="se"&gt;\
&lt;/span&gt;    &lt;span class="nb"&gt;chmod&lt;/span&gt; +x rustup-init&lt;span class="p"&gt;;&lt;/span&gt; &lt;span class="se"&gt;\
&lt;/span&gt;    ./rustup-init &lt;span class="nt"&gt;-y&lt;/span&gt; &lt;span class="nt"&gt;--no-modify-path&lt;/span&gt; &lt;span class="nt"&gt;--profile&lt;/span&gt; minimal &lt;span class="nt"&gt;--default-toolchain&lt;/span&gt; &lt;span class="nv"&gt;$RUST_VERSION&lt;/span&gt;&lt;span class="p"&gt;;&lt;/span&gt; &lt;span class="se"&gt;\
&lt;/span&gt;    &lt;span class="nb"&gt;rm &lt;/span&gt;rustup-init&lt;span class="p"&gt;;&lt;/span&gt; &lt;span class="se"&gt;\
&lt;/span&gt;    &lt;span class="nb"&gt;chmod&lt;/span&gt; &lt;span class="nt"&gt;-R&lt;/span&gt; a+w &lt;span class="nv"&gt;$RUSTUP_HOME&lt;/span&gt; &lt;span class="nv"&gt;$CARGO_HOME&lt;/span&gt;&lt;span class="p"&gt;;&lt;/span&gt; &lt;span class="se"&gt;\
&lt;/span&gt;    rustup &lt;span class="nt"&gt;--version&lt;/span&gt;&lt;span class="p"&gt;;&lt;/span&gt; &lt;span class="se"&gt;\
&lt;/span&gt;    cargo &lt;span class="nt"&gt;--version&lt;/span&gt;&lt;span class="p"&gt;;&lt;/span&gt; &lt;span class="se"&gt;\
&lt;/span&gt;    rustc &lt;span class="nt"&gt;--version&lt;/span&gt;&lt;span class="p"&gt;;&lt;/span&gt; &lt;span class="se"&gt;\
&lt;/span&gt;    update-ca-certificates&lt;span class="p"&gt;;&lt;/span&gt;

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



&lt;p&gt;The lines at the bottom of the default Rust Dockerfile that removes the apt cache and uninstalls packages were removed. This is necessary as future build steps will utilize the cache and packages and if we removed them it would increase the build time when the containers are not cached.&lt;/p&gt;

&lt;p&gt;Updating the CA certificates is also performed during this stage otherwise HTTPS calls may fail. I've experienced such failures when updating cargo and not having the CA certs up to date.&lt;/p&gt;

&lt;h2&gt;
  
  
  Elixir
&lt;/h2&gt;

&lt;p&gt;Following the same method as the Rust container, Elixir can build upon the &lt;code&gt;rust_builder&lt;/code&gt; stage using the official Elixir &lt;a href="https://github.com/c0b/docker-elixir/blob/3c7f7d55bf28a4f4689aac3d2e01bfa41173076d/1.10/slim/Dockerfile"&gt;Dockerfile&lt;/a&gt;.&lt;/p&gt;

&lt;p&gt;&lt;a href="https://res.cloudinary.com/practicaldev/image/fetch/s--fzUAPYM5--/c_limit%2Cf_auto%2Cfl_progressive%2Cq_auto%2Cw_880/https://github.com/c0b/docker-elixir" class="article-body-image-wrapper"&gt;&lt;img src="https://res.cloudinary.com/practicaldev/image/fetch/s--fzUAPYM5--/c_limit%2Cf_auto%2Cfl_progressive%2Cq_auto%2Cw_880/https://github.com/c0b/docker-elixir" alt="c0b/docker-elixir"&gt;&lt;/a&gt;&lt;/p&gt;

&lt;p&gt;To utilize a previously built stage it is referenced using the &lt;code&gt;FROM&lt;/code&gt; instruction. The example below will use the &lt;code&gt;rust_builder&lt;/code&gt; stage and the resulting changes will be named &lt;code&gt;elixir_builder&lt;/code&gt;.&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight"&gt;&lt;pre class="highlight docker"&gt;&lt;code&gt;&lt;span class="k"&gt;FROM&lt;/span&gt;&lt;span class="s"&gt; rust_builder AS elixir_builder&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;



&lt;p&gt;The contents below are copied from the Official Elixir Dockerfile again with slight modifications. Similar to the Rust stage, the commands to remove the apt cache and packages are removed. It is also in this stage that NodeJS 10 is installed from nodesource.&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight"&gt;&lt;pre class="highlight docker"&gt;&lt;code&gt;&lt;span class="k"&gt;FROM&lt;/span&gt;&lt;span class="s"&gt; rust_builder as elixir_builder&lt;/span&gt;

&lt;span class="c"&gt;# elixir expects utf8.&lt;/span&gt;
&lt;span class="k"&gt;ENV&lt;/span&gt;&lt;span class="s"&gt; ELIXIR_VERSION="v1.10.1" \&lt;/span&gt;
    LANG=C.UTF-8

&lt;span class="k"&gt;RUN &lt;/span&gt;&lt;span class="nb"&gt;set&lt;/span&gt; &lt;span class="nt"&gt;-xe&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="nv"&gt;ELIXIR_DOWNLOAD_URL&lt;/span&gt;&lt;span class="o"&gt;=&lt;/span&gt;&lt;span class="s2"&gt;"https://github.com/elixir-lang/elixir/archive/&lt;/span&gt;&lt;span class="k"&gt;${&lt;/span&gt;&lt;span class="nv"&gt;ELIXIR_VERSION&lt;/span&gt;&lt;span class="k"&gt;}&lt;/span&gt;&lt;span class="s2"&gt;.tar.gz"&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="nv"&gt;ELIXIR_DOWNLOAD_SHA256&lt;/span&gt;&lt;span class="o"&gt;=&lt;/span&gt;&lt;span class="s2"&gt;"bf10dc5cb084382384d69cc26b4f670a3eb0a97a6491182f4dcf540457f06c07"&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="nv"&gt;buildDeps&lt;/span&gt;&lt;span class="o"&gt;=&lt;/span&gt;&lt;span class="s1"&gt;' &lt;/span&gt;&lt;span class="se"&gt;\
&lt;/span&gt;&lt;span class="s1"&gt;        curl &lt;/span&gt;&lt;span class="se"&gt;\
&lt;/span&gt;&lt;span class="s1"&gt;        make &lt;/span&gt;&lt;span class="se"&gt;\
&lt;/span&gt;&lt;span class="s1"&gt;    '&lt;/span&gt; &lt;span class="se"&gt;\
&lt;/span&gt;    &lt;span class="o"&gt;&amp;amp;&amp;amp;&lt;/span&gt; apt-get update &lt;span class="se"&gt;\
&lt;/span&gt;    &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; &lt;span class="nt"&gt;--no-install-recommends&lt;/span&gt; &lt;span class="nv"&gt;$buildDeps&lt;/span&gt; &lt;span class="se"&gt;\
&lt;/span&gt;    &lt;span class="o"&gt;&amp;amp;&amp;amp;&lt;/span&gt; curl &lt;span class="nt"&gt;-fSL&lt;/span&gt; &lt;span class="nt"&gt;-o&lt;/span&gt; elixir-src.tar.gz &lt;span class="nv"&gt;$ELIXIR_DOWNLOAD_URL&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;echo&lt;/span&gt; &lt;span class="s2"&gt;"&lt;/span&gt;&lt;span class="nv"&gt;$ELIXIR_DOWNLOAD_SHA256&lt;/span&gt;&lt;span class="s2"&gt; elixir-src.tar.gz"&lt;/span&gt; | &lt;span class="nb"&gt;sha256sum&lt;/span&gt; &lt;span class="nt"&gt;-c&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;mkdir&lt;/span&gt; &lt;span class="nt"&gt;-p&lt;/span&gt; /usr/local/src/elixir &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;tar&lt;/span&gt; &lt;span class="nt"&gt;-xzC&lt;/span&gt; /usr/local/src/elixir &lt;span class="nt"&gt;--strip-components&lt;/span&gt;&lt;span class="o"&gt;=&lt;/span&gt;1 &lt;span class="nt"&gt;-f&lt;/span&gt; elixir-src.tar.gz &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;elixir-src.tar.gz &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;cd&lt;/span&gt; /usr/local/src/elixir &lt;span class="se"&gt;\
&lt;/span&gt;    &lt;span class="o"&gt;&amp;amp;&amp;amp;&lt;/span&gt; make &lt;span class="nb"&gt;install &lt;/span&gt;clean &lt;span class="se"&gt;\
&lt;/span&gt;  &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; git apt-transport-https ca-certificates &lt;span class="se"&gt;\
&lt;/span&gt;  &lt;span class="o"&gt;&amp;amp;&amp;amp;&lt;/span&gt; update-ca-certificates &lt;span class="se"&gt;\
&lt;/span&gt;  &lt;span class="o"&gt;&amp;amp;&amp;amp;&lt;/span&gt; curl &lt;span class="nt"&gt;-sL&lt;/span&gt; https://deb.nodesource.com/setup_10.x | bash - &lt;span class="se"&gt;\
&lt;/span&gt;  &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="p"&gt;;&lt;/span&gt;

&lt;span class="k"&gt;CMD&lt;/span&gt;&lt;span class="s"&gt; ["iex"]&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;



&lt;h2&gt;
  
  
  Application configuration
&lt;/h2&gt;

&lt;p&gt;Multiple environment variables are used for the application container setup. Using the combination of &lt;code&gt;ARG&lt;/code&gt; and &lt;code&gt;ENV&lt;/code&gt; allows the access of the variables during build &lt;strong&gt;and&lt;/strong&gt; execution. These are set via the Render dashboard.&lt;/p&gt;

&lt;h3&gt;
  
  
  Build variables
&lt;/h3&gt;

&lt;p&gt;Environment variables required for building the container are:&lt;/p&gt;

&lt;p&gt;&lt;code&gt;APP_NAME&lt;/code&gt; - The name of your application, used when starting. Utilized in the final step of the Dockerfile.&lt;/p&gt;

&lt;p&gt;&lt;code&gt;PORT&lt;/code&gt; - Port that will serve the application&lt;/p&gt;

&lt;h3&gt;
  
  
  Run time variables
&lt;/h3&gt;

&lt;p&gt;The application must be configured to utilize the variables available during &lt;strong&gt;run time&lt;/strong&gt;. These variables are:&lt;/p&gt;

&lt;p&gt;&lt;code&gt;DATABASE_URL&lt;/code&gt; - The URL which allows the application to connect to the database.&lt;/p&gt;

&lt;p&gt;&lt;code&gt;POOL_SIZE&lt;/code&gt; - The number of connections to the database the application will establish.&lt;/p&gt;

&lt;p&gt;&lt;code&gt;SECRET_KEY_BASE&lt;/code&gt; - Base string used for encryption/decryption of secrets&lt;/p&gt;

&lt;p&gt;&lt;code&gt;PORT&lt;/code&gt; - Port that will serve the application&lt;/p&gt;

&lt;p&gt;These can bet set in the &lt;code&gt;config/releases.exs&lt;/code&gt; file using &lt;code&gt;System.get_env/1&lt;/code&gt;.&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight"&gt;&lt;pre class="highlight elixir"&gt;&lt;code&gt;&lt;span class="n"&gt;database_url&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt;
  &lt;span class="no"&gt;System&lt;/span&gt;&lt;span class="o"&gt;.&lt;/span&gt;&lt;span class="n"&gt;get_env&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="s2"&gt;"DATABASE_URL"&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt; &lt;span class="o"&gt;||&lt;/span&gt;
    &lt;span class="k"&gt;raise&lt;/span&gt; &lt;span class="sd"&gt;"""
    environment variable DATABASE_URL is missing.
    For example: ecto://USER:PASS@HOST/DATABASE
    """&lt;/span&gt;

&lt;span class="n"&gt;config&lt;/span&gt; &lt;span class="ss"&gt;:my_app&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="no"&gt;MyApp&lt;/span&gt;&lt;span class="o"&gt;.&lt;/span&gt;&lt;span class="no"&gt;Repo&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;
  &lt;span class="ss"&gt;url:&lt;/span&gt; &lt;span class="n"&gt;database_url&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;
  &lt;span class="ss"&gt;pool_size:&lt;/span&gt; &lt;span class="no"&gt;String&lt;/span&gt;&lt;span class="o"&gt;.&lt;/span&gt;&lt;span class="n"&gt;to_integer&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="no"&gt;System&lt;/span&gt;&lt;span class="o"&gt;.&lt;/span&gt;&lt;span class="n"&gt;get_env&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="s2"&gt;"POOL_SIZE"&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt; &lt;span class="o"&gt;||&lt;/span&gt; &lt;span class="s2"&gt;"10"&lt;/span&gt;&lt;span class="p"&gt;),&lt;/span&gt;
  &lt;span class="ss"&gt;ssl:&lt;/span&gt; &lt;span class="no"&gt;true&lt;/span&gt;

&lt;span class="n"&gt;secret_key_base&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt;
  &lt;span class="no"&gt;System&lt;/span&gt;&lt;span class="o"&gt;.&lt;/span&gt;&lt;span class="n"&gt;get_env&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="s2"&gt;"SECRET_KEY_BASE"&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt; &lt;span class="o"&gt;||&lt;/span&gt;
    &lt;span class="k"&gt;raise&lt;/span&gt; &lt;span class="sd"&gt;"""
    environment variable SECRET_KEY_BASE is missing.
    You can generate one by calling: mix phx.gen.secret
    """&lt;/span&gt;

&lt;span class="n"&gt;config&lt;/span&gt; &lt;span class="ss"&gt;:my_app&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="no"&gt;MyAppWeb&lt;/span&gt;&lt;span class="o"&gt;.&lt;/span&gt;&lt;span class="no"&gt;Endpoint&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;
  &lt;span class="ss"&gt;http:&lt;/span&gt; &lt;span class="p"&gt;[&lt;/span&gt;&lt;span class="ss"&gt;:inet6&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="ss"&gt;port:&lt;/span&gt; &lt;span class="no"&gt;String&lt;/span&gt;&lt;span class="o"&gt;.&lt;/span&gt;&lt;span class="n"&gt;to_integer&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="no"&gt;System&lt;/span&gt;&lt;span class="o"&gt;.&lt;/span&gt;&lt;span class="n"&gt;get_env&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="s2"&gt;"PORT"&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt; &lt;span class="o"&gt;||&lt;/span&gt; &lt;span class="s2"&gt;"4000"&lt;/span&gt;&lt;span class="p"&gt;)],&lt;/span&gt;
  &lt;span class="ss"&gt;secret_key_base:&lt;/span&gt; &lt;span class="n"&gt;secret_key_base&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;
  &lt;span class="ss"&gt;server:&lt;/span&gt; &lt;span class="no"&gt;true&lt;/span&gt;

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



&lt;p&gt;The &lt;code&gt;host&lt;/code&gt; must also be set in &lt;code&gt;config/prod.exs&lt;/code&gt;.&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight"&gt;&lt;pre class="highlight elixir"&gt;&lt;code&gt;&lt;span class="n"&gt;config&lt;/span&gt; &lt;span class="ss"&gt;:my_app&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="no"&gt;MyAppWeb&lt;/span&gt;&lt;span class="o"&gt;.&lt;/span&gt;&lt;span class="no"&gt;Endpoint&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;
  &lt;span class="ss"&gt;url:&lt;/span&gt; &lt;span class="p"&gt;[&lt;/span&gt;&lt;span class="ss"&gt;host:&lt;/span&gt; &lt;span class="no"&gt;System&lt;/span&gt;&lt;span class="o"&gt;.&lt;/span&gt;&lt;span class="n"&gt;get_env&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="s2"&gt;"RENDER_EXTERNAL_HOSTNAME"&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt; &lt;span class="o"&gt;||&lt;/span&gt; &lt;span class="s2"&gt;"example.com"&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="ss"&gt;port:&lt;/span&gt; &lt;span class="mi"&gt;80&lt;/span&gt;&lt;span class="p"&gt;],&lt;/span&gt;
  &lt;span class="ss"&gt;cache_static_manifest:&lt;/span&gt; &lt;span class="s2"&gt;"priv/static/cache_manifest.json"&lt;/span&gt;

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



&lt;h2&gt;
  
  
  Building a release
&lt;/h2&gt;

&lt;p&gt;The final build step is using &lt;code&gt;mix release&lt;/code&gt; to build and package the Elixir application. The current working directory is used to copy the source code into the containers &lt;code&gt;/app&lt;/code&gt; directory and then the release is built. This step utilizes the results of the &lt;code&gt;elixir_builder&lt;/code&gt; step and named it &lt;code&gt;app_builder&lt;/code&gt;.&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight"&gt;&lt;pre class="highlight docker"&gt;&lt;code&gt;&lt;span class="k"&gt;FROM&lt;/span&gt;&lt;span class="s"&gt; elixir_builder as app_builder&lt;/span&gt;

&lt;span class="k"&gt;RUN &lt;/span&gt;&lt;span class="nb"&gt;mkdir&lt;/span&gt; /app
&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; . .&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="k"&gt;RUN &lt;/span&gt;&lt;span class="nb"&gt;set&lt;/span&gt; &lt;span class="nt"&gt;-xe&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="se"&gt;\
&lt;/span&gt;  &lt;span class="o"&gt;&amp;amp;&amp;amp;&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 &lt;span class="k"&gt;do &lt;/span&gt;deps.get, compile &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="nt"&gt;--prefix&lt;/span&gt; ./assets &lt;span class="se"&gt;\
&lt;/span&gt;  &lt;span class="o"&gt;&amp;amp;&amp;amp;&lt;/span&gt; npm run deploy &lt;span class="nt"&gt;--prefix&lt;/span&gt; ./assets &lt;span class="se"&gt;\
&lt;/span&gt;  &lt;span class="o"&gt;&amp;amp;&amp;amp;&lt;/span&gt; mix &lt;span class="k"&gt;do &lt;/span&gt;phx.digest, release &lt;span class="nt"&gt;--overwrite&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;



&lt;h2&gt;
  
  
  Building the app run time container
&lt;/h2&gt;

&lt;p&gt;Now that the application release is built we can throw away our previous steps to ensure we have the smallest container possible. Locales and environment variables are setup along with the apt cache being removed to keep the final container size down.&lt;/p&gt;

&lt;h3&gt;
  
  
  Privileged access
&lt;/h3&gt;

&lt;p&gt;The application is ran as the &lt;code&gt;nobody&lt;/code&gt; user which does not have permissions to bind to privileged ports. Although Render does allow this type of binding I avoided it as it is unnecessary and I prefer to run applications with as few permissions as possible.&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight"&gt;&lt;pre class="highlight docker"&gt;&lt;code&gt;&lt;span class="k"&gt;FROM&lt;/span&gt;&lt;span class="s"&gt; debian:buster-slim&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;ARG&lt;/span&gt;&lt;span class="s"&gt; PORT&lt;/span&gt;
&lt;span class="k"&gt;ARG&lt;/span&gt;&lt;span class="s"&gt; SECRET_KEY_BASE&lt;/span&gt;
&lt;span class="k"&gt;ARG&lt;/span&gt;&lt;span class="s"&gt; DATABASE_URL&lt;/span&gt;
&lt;span class="k"&gt;ARG&lt;/span&gt;&lt;span class="s"&gt; POOL_SIZE&lt;/span&gt;

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

&lt;span class="k"&gt;ENV&lt;/span&gt;&lt;span class="s"&gt; LANG=en_US.UTF-8 \&lt;/span&gt;
  LANGUAGE=en_US.UTF-8 \
  LC_ALL=en_US.UTF-8 \
  MIX_ENV=prod \
  SHELL=/bin/bash \
  APP_NAME=$APP_NAME \
  PORT=$PORT \
  HOME=/app \
  SECRET_KEY_BASE=$SECRET_KEY_BASE \
  DATABASE_URL=$DATABASE_URL \
  POOL_SIZE=$POOL_SIZE

&lt;span class="c"&gt;# Setup locales to prevent VM from starting with latin1&lt;/span&gt;
&lt;span class="c"&gt;# Install application runtime deps&lt;/span&gt;
&lt;span class="k"&gt;RUN &lt;/span&gt;&lt;span class="nb"&gt;set&lt;/span&gt; &lt;span class="nt"&gt;-xe&lt;/span&gt; &lt;span class="se"&gt;\
&lt;/span&gt;  &lt;span class="o"&gt;&amp;amp;&amp;amp;&lt;/span&gt; apt-get update &lt;span class="se"&gt;\
&lt;/span&gt;  &lt;span class="o"&gt;&amp;amp;&amp;amp;&lt;/span&gt; &lt;span class="nv"&gt;DEBIAN_FRONTEND&lt;/span&gt;&lt;span class="o"&gt;=&lt;/span&gt;noninteractive apt-get &lt;span class="nb"&gt;install&lt;/span&gt; &lt;span class="nt"&gt;-y&lt;/span&gt; &lt;span class="nt"&gt;--no-install-recommends&lt;/span&gt; openssl ca-certificates locales &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;sed&lt;/span&gt; &lt;span class="nt"&gt;-i&lt;/span&gt; &lt;span class="nt"&gt;-e&lt;/span&gt; &lt;span class="s1"&gt;'s/# en_US.UTF-8 UTF-8/en_US.UTF-8 UTF-8/'&lt;/span&gt; /etc/locale.gen &lt;span class="se"&gt;\
&lt;/span&gt;  &lt;span class="o"&gt;&amp;amp;&amp;amp;&lt;/span&gt; dpkg-reconfigure &lt;span class="nt"&gt;--frontend&lt;/span&gt;&lt;span class="o"&gt;=&lt;/span&gt;noninteractive locales &lt;span class="se"&gt;\
&lt;/span&gt;  &lt;span class="o"&gt;&amp;amp;&amp;amp;&lt;/span&gt; update-locale &lt;span class="nv"&gt;LANG&lt;/span&gt;&lt;span class="o"&gt;=&lt;/span&gt;en_US.UTF-8 &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; /var/lib/apt/lists/&lt;span class="k"&gt;*&lt;/span&gt;

&lt;span class="k"&gt;COPY&lt;/span&gt;&lt;span class="s"&gt; --from=app_builder /app/_build/prod/rel/${APP_NAME} .&lt;/span&gt;

&lt;span class="k"&gt;EXPOSE&lt;/span&gt;&lt;span class="s"&gt; ${PORT}&lt;/span&gt;

&lt;span class="k"&gt;RUN &lt;/span&gt;&lt;span class="nb"&gt;chown&lt;/span&gt; &lt;span class="nt"&gt;-R&lt;/span&gt; nobody: /app
&lt;span class="k"&gt;USER&lt;/span&gt;&lt;span class="s"&gt; nobody&lt;/span&gt;

&lt;span class="k"&gt;CMD&lt;/span&gt;&lt;span class="s"&gt; bin/${APP_NAME} start&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;



&lt;h2&gt;
  
  
  Testing locally
&lt;/h2&gt;

&lt;p&gt;Before setting up your Render application it's best to ensure the container is built properly. The two build variables detailed earlier will need to be passed to docker using the &lt;code&gt;--build-env&lt;/code&gt; argument. For this example my project is named &lt;code&gt;hades&lt;/code&gt;.&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight"&gt;&lt;pre class="highlight shell"&gt;&lt;code&gt;docker build &lt;span class="nt"&gt;--build-arg&lt;/span&gt; &lt;span class="nv"&gt;PORT&lt;/span&gt;&lt;span class="o"&gt;=&lt;/span&gt;10000 &lt;span class="nt"&gt;--build-arg&lt;/span&gt; &lt;span class="nv"&gt;APP_NAME&lt;/span&gt;&lt;span class="o"&gt;=&lt;/span&gt;hades &lt;span class="nb"&gt;.&lt;/span&gt; &lt;span class="nt"&gt;-t&lt;/span&gt; hades
&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;



&lt;p&gt;To run the container I found specifying the environment variables in a &lt;code&gt;env.list&lt;/code&gt; file to work best. The contents of this file are in the format of &lt;code&gt;KEY=value&lt;/code&gt;.&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight"&gt;&lt;pre class="highlight shell"&gt;&lt;code&gt;&lt;span class="nv"&gt;SECRET_KEY&lt;/span&gt;&lt;span class="o"&gt;=&lt;/span&gt;jBZE5O2W0EsMQ7dCQBO7ZbOchN9ORFG82k1LVlRF/9qjs9iqQZGg9LE59n4y5tTV
&lt;span class="nv"&gt;POOL_SIZE&lt;/span&gt;&lt;span class="o"&gt;=&lt;/span&gt;10
&lt;span class="nv"&gt;DATABASE_URL&lt;/span&gt;&lt;span class="o"&gt;=&lt;/span&gt;postgres://test_user:test_password@postgres.render.com/test_database
&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;



&lt;p&gt;The container is then started with &lt;code&gt;docker run&lt;/code&gt; specifying the &lt;code&gt;env.list&lt;/code&gt; file:&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight"&gt;&lt;pre class="highlight shell"&gt;&lt;code&gt;docker run &lt;span class="nt"&gt;--env-file&lt;/span&gt;&lt;span class="o"&gt;=&lt;/span&gt;env.list hades
&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;



&lt;p&gt;A full build and run locally was captured using asciinema.&lt;/p&gt;

&lt;p&gt;&lt;a href="https://asciinema.org/a/Ztr2TlafbHrVRLpO23NyZnZLx"&gt;&lt;img src="https://res.cloudinary.com/practicaldev/image/fetch/s--FvCAk3qs--/c_limit%2Cf_auto%2Cfl_progressive%2Cq_auto%2Cw_880/https://asciinema.org/a/Ztr2TlafbHrVRLpO23NyZnZLx.svg" alt="asciicast"&gt;&lt;/a&gt;&lt;/p&gt;

&lt;h2&gt;
  
  
  Configuring Render
&lt;/h2&gt;

&lt;p&gt;When a new web service is created on Render the Environment must be set to Docker. If your Dockerfile is in the root of your repository you can continue on to setting the environment variables.&lt;/p&gt;

&lt;p&gt;Render supports storing your Dockerfile anywhere in your repository. This is set using the &lt;code&gt;Dockerfile Path&lt;/code&gt; under the &lt;code&gt;Advanced&lt;/code&gt; section of the setup. The &lt;code&gt;Docker Build Context Directory&lt;/code&gt; must also be set if the root of your repository shouldn't be used when building, this article assumes the root directory is used for both settings.&lt;/p&gt;

&lt;h3&gt;
  
  
  Setting environment variables
&lt;/h3&gt;

&lt;p&gt;The environment variables described within this article must be manually set per application that is hosted on Render. You are free to pick any values for &lt;code&gt;SECRET_KEY_BASE&lt;/code&gt; / &lt;code&gt;PORT&lt;/code&gt; however the remaining variables should be set depending on your database / application.&lt;/p&gt;

&lt;p&gt;&lt;code&gt;POOL_SIZE&lt;/code&gt; should be set according to the connection limit governed by the database tier.&lt;/p&gt;

&lt;p&gt;&lt;code&gt;DATABASE_URL&lt;/code&gt; is set using the &lt;code&gt;Internal Connection String&lt;/code&gt; from the database page.&lt;/p&gt;

&lt;p&gt;&lt;code&gt;APP_NAME&lt;/code&gt; should match your application name.&lt;/p&gt;

&lt;p&gt;&lt;code&gt;RENDER_EXTERNAL_HOSTNAME&lt;/code&gt; is only used if you are using the Render subdomain. If you are not then I would hard code the value in the config file.&lt;/p&gt;

&lt;p&gt;Those are the steps necessary to build and deploy an Elixir project with Rust NIFs on Render.com. Anytime you push changes to your configured branch a new container will be built and deployed.&lt;/p&gt;

&lt;h2&gt;
  
  
  TLDR
&lt;/h2&gt;

&lt;p&gt;The complete Dockerfile is available on Gitlab: &lt;a href="https://gitlab.com/fkumro/elixir-rust-render"&gt;https://gitlab.com/fkumro/elixir-rust-render&lt;/a&gt;&lt;/p&gt;

&lt;h2&gt;
  
  
  Notes:
&lt;/h2&gt;

&lt;ul&gt;
&lt;li&gt;The build time on Render will most likely be much slower than your local machine. The builds on the $7 plan took around 17 minutes and docker containers don't seem to be cached. Hopefully Render improves their build machines in the future.&lt;/li&gt;
&lt;li&gt;Migrations are not covered in this article.&lt;/li&gt;
&lt;li&gt;The application would benefit from a health endpoint that Render can use to determine if the container should be killed and a new one started.&lt;/li&gt;
&lt;/ul&gt;

</description>
      <category>elixir</category>
      <category>docker</category>
      <category>rust</category>
      <category>rendercom</category>
    </item>
  </channel>
</rss>
