<?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: Alastair Measures</title>
    <description>The latest articles on DEV Community by Alastair Measures (@alastairmeasures).</description>
    <link>https://dev.to/alastairmeasures</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%2F603155%2F0ead90d1-ff97-4186-bd9a-54ce67bda893.jpg</url>
      <title>DEV Community: Alastair Measures</title>
      <link>https://dev.to/alastairmeasures</link>
    </image>
    <atom:link rel="self" type="application/rss+xml" href="https://dev.to/feed/alastairmeasures"/>
    <language>en</language>
    <item>
      <title>Dockerizing Phoenix Development (6) Installing Phoenix</title>
      <dc:creator>Alastair Measures</dc:creator>
      <pubDate>Sun, 30 May 2021 18:51:43 +0000</pubDate>
      <link>https://dev.to/alastairmeasures/dockerizing-phoenix-development-step-6-installing-phoenix-266</link>
      <guid>https://dev.to/alastairmeasures/dockerizing-phoenix-development-step-6-installing-phoenix-266</guid>
      <description>&lt;p&gt;The database is on tap, the elixir image is ready and sharp observers, &lt;em&gt;on their third espresso&lt;/em&gt;, will notice: &lt;strong&gt;Phoenix is still not present!&lt;/strong&gt;&lt;/p&gt;

&lt;p&gt;To get Phoenix installed we need to:&lt;/p&gt;

&lt;ul&gt;
&lt;li&gt;have the containers running&lt;/li&gt;
&lt;li&gt;sign in to the &lt;strong&gt;web&lt;/strong&gt; container as &lt;strong&gt;devuser&lt;/strong&gt;
&lt;/li&gt;
&lt;li&gt;install the Erlang and Elixir package managers&lt;/li&gt;
&lt;li&gt;install the Phoenix package (and dependencies).&lt;/li&gt;
&lt;/ul&gt;

&lt;p&gt;These things go into hidden folders within the (container) &lt;strong&gt;/apps&lt;/strong&gt; folder because it is the home folder for the &lt;strong&gt;devuser&lt;/strong&gt; account used for development.&lt;/p&gt;

&lt;ul&gt;
&lt;li&gt;After this, the standard &lt;strong&gt;mix&lt;/strong&gt; commands can be used to initiate projects, run migrations, run the web servers and so on.&lt;/li&gt;
&lt;li&gt;From this point, the standard text books for Phoenix 1.5 (e.g. McCord, Tate &amp;amp; Valim) can be followed without problems.&lt;/li&gt;
&lt;/ul&gt;

&lt;h2&gt;
  
  
  Installing
&lt;/h2&gt;

&lt;h3&gt;
  
  
  Start the containers:
&lt;/h3&gt;

&lt;p&gt;From the command line:&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight plaintext"&gt;&lt;code&gt;docker-compose  up  -d
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;h3&gt;
  
  
  Connect to the &lt;strong&gt;web&lt;/strong&gt; container shell
&lt;/h3&gt;

&lt;p&gt;From the command line:&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight plaintext"&gt;&lt;code&gt;docker exec  -u devuser  -ti  myp_dev_web_1  /bin/ash
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;h3&gt;
  
  
  Install Erlang package manager called Rebar
&lt;/h3&gt;



&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight plaintext"&gt;&lt;code&gt;mix local.rebar --force
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;h3&gt;
  
  
  Install Elixir package manager called Hex
&lt;/h3&gt;



&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight plaintext"&gt;&lt;code&gt;mix local.hex --force
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;h3&gt;
  
  
  Install Phoenix tool packages
&lt;/h3&gt;



&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight plaintext"&gt;&lt;code&gt;mix archive.install hex phx_new 1.6.10 --force
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;ul&gt;
&lt;li&gt;
&lt;em&gt;By the time you read this: version 1.6.10 may no longer be ideal so review what is the latest stable edition: &lt;a href="https://hexdocs.pm/phoenix/Phoenix.html" rel="noopener noreferrer"&gt;https://hexdocs.pm/phoenix/Phoenix.html&lt;/a&gt;&lt;/em&gt;.&lt;/li&gt;
&lt;/ul&gt;

&lt;h2&gt;
  
  
  Run up a fresh Phoenix project
&lt;/h2&gt;



&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight plaintext"&gt;&lt;code&gt;mix phx.new myp
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;All being well, your project is now rolling and you will need to adjust the database configuration for the project.&lt;/p&gt;

&lt;ul&gt;
&lt;li&gt;The database configuration should reflect the database user (myp_user) and database instance (myp_dev) created earlier.&lt;/li&gt;
&lt;li&gt;The database configuration should also reflect that the database host should be &lt;strong&gt;db&lt;/strong&gt; &lt;em&gt;(the service name from the &lt;strong&gt;docker-compose.yml&lt;/strong&gt; file) rather than &lt;strong&gt;localhost&lt;/strong&gt;!&lt;/em&gt;
&lt;/li&gt;
&lt;/ul&gt;

&lt;p&gt;The Elixir driver for PostgreSQL is postgrex and there are some relevant extensions to consider at this point: &lt;/p&gt;

&lt;ul&gt;
&lt;li&gt;&lt;a href="https://github.com/bryanjos/geo_postgis" rel="noopener noreferrer"&gt;geo_postgis&lt;/a&gt;&lt;/li&gt;
&lt;li&gt;&lt;a href="https://github.com/bryanjos/geo" rel="noopener noreferrer"&gt;geo&lt;/a&gt;&lt;/li&gt;
&lt;li&gt;&lt;a href="https://github.com/pkinney/topo" rel="noopener noreferrer"&gt;topo&lt;/a&gt;&lt;/li&gt;
&lt;li&gt;&lt;a href="https://github.com/bryanjos/open_location_code" rel="noopener noreferrer"&gt;open_location_code&lt;/a&gt;&lt;/li&gt;
&lt;/ul&gt;

&lt;h2&gt;
  
  
  Remarks
&lt;/h2&gt;

&lt;ul&gt;
&lt;li&gt;This tutorial has been run through to test that it works.  Any problems, leave a comment and I will respond.&lt;/li&gt;
&lt;li&gt;This tutorial works through a few awkward challenges; these solutions may have saved you some time.  If you are feeling generous, you could &lt;strong&gt;&lt;a href="https://buymeacoffee.com/alastairm" rel="noopener noreferrer"&gt;buy me a coffee&lt;/a&gt;!&lt;/strong&gt; &lt;/li&gt;
&lt;/ul&gt;

</description>
      <category>docker</category>
      <category>postgres</category>
      <category>phoenix</category>
      <category>postgis</category>
    </item>
    <item>
      <title>Dockerizing Phoenix Development (5) Scripting the images</title>
      <dc:creator>Alastair Measures</dc:creator>
      <pubDate>Sun, 30 May 2021 18:50:07 +0000</pubDate>
      <link>https://dev.to/alastairmeasures/dockerizing-phoenix-development-step-5-scripting-the-images-2imo</link>
      <guid>https://dev.to/alastairmeasures/dockerizing-phoenix-development-step-5-scripting-the-images-2imo</guid>
      <description>&lt;p&gt;This extends the &lt;strong&gt;docker-compose.yml&lt;/strong&gt; that appeared in step 3.&lt;/p&gt;

&lt;h2&gt;
  
  
  The Dockerfile (./myp_dev/docker-compose.yml)
&lt;/h2&gt;



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

volumes:
  postgis13_data:

networks:
  myp_net:

services:

  db:
    image: postgis/postgis:13-3.1-alpine
    networks:
      - myp_net
    environment:
#     - POSTGRES_USER=postgres
      - POSTGRES_PASSWORD=postgres
#     - POSTGRES_DB=postgres
    ports:
      - 5432:5432
    volumes:
      - postgis13_data:/var/lib/postgresql/data/

  web: 
    build:
      context: .
      dockerfile: Dockerfile.alpine
    networks:
      - myp_net
    ports:
      - 4000:4000
    depends_on: 
      - db
    volumes:
      - ./source:/apps

# end
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;As docker-compose scripts go: this is about as simple as it gets. Even someone with a passing awareness of docker should be able to read this.&lt;/p&gt;

&lt;h2&gt;
  
  
  Build image from Dockerfile(s)
&lt;/h2&gt;



&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight plaintext"&gt;&lt;code&gt;docker-compose --build
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;h2&gt;
  
  
  Remarks
&lt;/h2&gt;

&lt;ul&gt;
&lt;li&gt;The system defined by this script is unlikely to conflict with other running systems; other than where it offers service on ports exposed onto the &lt;strong&gt;localhost&lt;/strong&gt;.&lt;/li&gt;
&lt;/ul&gt;

</description>
      <category>docker</category>
      <category>postgis</category>
      <category>phoenix</category>
      <category>postgres</category>
    </item>
    <item>
      <title>Dockerizing Phoenix Development (4) The Dockerfile</title>
      <dc:creator>Alastair Measures</dc:creator>
      <pubDate>Sun, 30 May 2021 18:49:14 +0000</pubDate>
      <link>https://dev.to/alastairmeasures/dockerizing-phoenix-development-step-4-the-dockerfile-3i29</link>
      <guid>https://dev.to/alastairmeasures/dockerizing-phoenix-development-step-4-the-dockerfile-3i29</guid>
      <description>&lt;p&gt;This step assembles a Dockerfile in order to develop a Phoenix web server.  It lists the Dockerfile and then explains key lines.  You &lt;strong&gt;will probably&lt;/strong&gt; need to make some adjustments for your own use, so check the explanations.&lt;/p&gt;

&lt;h2&gt;
  
  
  The Dockerfile (./myp_dev/Dockerfile.alpine)
&lt;/h2&gt;



&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight plaintext"&gt;&lt;code&gt;FROM elixir:1.12-alpine

LABEL maintainer="me_myself_i@work"
LABEL version_date="2021-05-20"

RUN apk add --no-cache --update \
        git \
        inotify-tools \
        libpq postgresql-client \
        nodejs npm yarn

ENV  USER="devuser"  UID="1000"  GID="1000"

RUN addgroup  -g $GID  -S $USER  &amp;amp;&amp;amp; \
    adduser  -h /apps  -g ""  -G $USER  -S  -D  -u $UID "$USER"

USER $UID:$GID

ENV PATH="/usr/local/lib/elixir/bin:/usr/local/lib/erlang/bin:$PATH"
ENV PATH="/apps/.cache/rebar3/bin:$PATH"

VOLUME /apps
WORKDIR /apps
EXPOSE 4000/tcp

CMD sleep 50000
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;h2&gt;
  
  
  Lines Explained
&lt;/h2&gt;



&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight plaintext"&gt;&lt;code&gt;FROM elixir:1.12-alpine
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;ul&gt;
&lt;li&gt;&lt;em&gt;Note this means use of the &lt;a href="https://wiki.alpinelinux.org/wiki/Alpine_Linux_package_management" rel="noopener noreferrer"&gt;apk&lt;/a&gt; package manager for &lt;a href="https://www.alpinelinux.org/" rel="noopener noreferrer"&gt;Alpine Linux&lt;/a&gt; rather than the &lt;strong&gt;apt&lt;/strong&gt; utility used with Debian and Ubuntu.  There is a full searchable library of &lt;a href="https://pkgs.alpinelinux.org/packages" rel="noopener noreferrer"&gt;packages&lt;/a&gt; available for Alpine Linux.&lt;/em&gt;&lt;/li&gt;
&lt;li&gt;
&lt;em&gt;By the time you read this, later editions may be &lt;a href="https://hub.docker.com/_/elixir" rel="noopener noreferrer"&gt;available&lt;/a&gt; so &lt;strong&gt;adjust as necessary&lt;/strong&gt;&lt;/em&gt;.
&lt;/li&gt;
&lt;/ul&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight plaintext"&gt;&lt;code&gt;RUN apk add --no-cache --update \
        git \
        inotify-tools \
        libpq postgresql-client \
        nodejs npm yarn
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;Packages as follows:&lt;/p&gt;

&lt;ul&gt;
&lt;li&gt;&lt;p&gt;&lt;strong&gt;&lt;a href="https://pkgs.alpinelinux.org/package/edge/main/x86_64/git" rel="noopener noreferrer"&gt;git&lt;/a&gt;&lt;/strong&gt; &lt;em&gt;is useful for automated download of libraries, as well as uploading code to &lt;a href="https://www.github.com" rel="noopener noreferrer"&gt;github&lt;/a&gt; et cetera.&lt;/em&gt;&lt;/p&gt;&lt;/li&gt;
&lt;li&gt;&lt;p&gt;&lt;strong&gt;&lt;a href="https://pkgs.alpinelinux.org/package/edge/main/x86_64/inotify-tools" rel="noopener noreferrer"&gt;inotify-tools&lt;/a&gt;&lt;/strong&gt; &lt;em&gt;adds into the container kernel so that changes to files can be detected by a running program within the container&lt;/em&gt;.&lt;/p&gt;&lt;/li&gt;
&lt;li&gt;&lt;p&gt;&lt;strong&gt;&lt;a href="https://pkgs.alpinelinux.org/package/edge/main/x86_64/libpq" rel="noopener noreferrer"&gt;libpq&lt;/a&gt;&lt;/strong&gt; &lt;em&gt;is the shared object/ DLL for access to PostgreSQL&lt;/em&gt;. &lt;/p&gt;&lt;/li&gt;
&lt;li&gt;&lt;p&gt;&lt;strong&gt;&lt;a href="https://pkgs.alpinelinux.org/package/edge/main/x86_64/postgresql-client" rel="noopener noreferrer"&gt;postgresql-client&lt;/a&gt;&lt;/strong&gt; &lt;em&gt;adds in the PostgreSQL command line tools such as &lt;strong&gt;psql&lt;/strong&gt;&lt;/em&gt;.  &lt;em&gt;This is not strictly needed and adds ~9MB to the image, but it is convenient to have on hand.&lt;/em&gt;&lt;/p&gt;&lt;/li&gt;
&lt;li&gt;&lt;p&gt;&lt;strong&gt;&lt;a href="https://pkgs.alpinelinux.org/package/edge/main/x86_64/nodejs" rel="noopener noreferrer"&gt;nodejs&lt;/a&gt;&lt;/strong&gt; &lt;em&gt;Javascript interpreter&lt;/em&gt;.&lt;/p&gt;&lt;/li&gt;
&lt;li&gt;&lt;p&gt;&lt;strong&gt;&lt;a href="https://pkgs.alpinelinux.org/package/edge/main/x86_64/npm" rel="noopener noreferrer"&gt;npm&lt;/a&gt;&lt;/strong&gt; &amp;amp; &lt;strong&gt;&lt;a href="https://pkgs.alpinelinux.org/package/edge/community/x86_64/yarn" rel="noopener noreferrer"&gt;yarn&lt;/a&gt;&lt;/strong&gt; &lt;em&gt;package managers for JavaScript&lt;/em&gt;.&lt;br&gt;
&lt;/p&gt;&lt;/li&gt;
&lt;/ul&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight plaintext"&gt;&lt;code&gt;ENV  USER="devuser"  UID="1000"  GID="1000"
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;ul&gt;
&lt;li&gt;&lt;p&gt;&lt;em&gt;Set some environment variables for use in setting up a user account for you as developer.&lt;/em&gt;&lt;/p&gt;&lt;/li&gt;
&lt;li&gt;&lt;p&gt;&lt;em&gt;Matching the UID &amp;amp; GID between your host user account and the developer account in the image is key to using IDE's and other tools. You &lt;strong&gt;MUST&lt;/strong&gt; use your own UID and GID here!&lt;/em&gt;&lt;br&gt;
&lt;/p&gt;&lt;/li&gt;
&lt;/ul&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight plaintext"&gt;&lt;code&gt;RUN addgroup  -g $GID  -S $USER &amp;amp;&amp;amp; \
RUN adduser  -h /apps  -g ""  -G $USER  -S  -D  -u $UID "$USER"
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;ul&gt;
&lt;li&gt;&lt;p&gt;&lt;em&gt;These lines add a new group and a new user within that group.&lt;/em&gt;&lt;/p&gt;&lt;/li&gt;
&lt;li&gt;&lt;p&gt;&lt;em&gt;Alpine Linux uses the &lt;a href="https://www.busybox.net" rel="noopener noreferrer"&gt;BusyBox&lt;/a&gt; tools to do this; which are different to the Debian/ Ubuntu ones!&lt;/em&gt;  &lt;em&gt;&lt;a href="https://www.busybox.net/downloads/BusyBox.html" rel="noopener noreferrer"&gt;Documentation is available&lt;/a&gt;.&lt;/em&gt;&lt;br&gt;
&lt;/p&gt;&lt;/li&gt;
&lt;/ul&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight plaintext"&gt;&lt;code&gt;USER $UID:$GID
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;ul&gt;
&lt;li&gt;
&lt;em&gt;The remaining few lines are completed as the &lt;strong&gt;devuser&lt;/strong&gt;. So signing in as &lt;strong&gt;devuser&lt;/strong&gt; will have the $PATH, and start  in the WORKDIR that you would expect.&lt;/em&gt;
&lt;/li&gt;
&lt;/ul&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight plaintext"&gt;&lt;code&gt;ENV PATH="/usr/local/lib/elixir/bin:/usr/local/lib/erlang/bin:$PATH"
ENV PATH="/apps/.cache/rebar3/bin:$PATH"
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;ul&gt;
&lt;li&gt;
&lt;em&gt;Adds Elixir and Erlang into the $PATH.&lt;/em&gt;
&lt;/li&gt;
&lt;/ul&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight plaintext"&gt;&lt;code&gt;VOLUME /apps
WORKDIR /apps
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;ul&gt;
&lt;li&gt;&lt;p&gt;&lt;em&gt;The &lt;strong&gt;/apps/&lt;/strong&gt; folder within the container will be the  $HOME folder of the &lt;strong&gt;devuser&lt;/strong&gt; account.&lt;/em&gt; &lt;/p&gt;&lt;/li&gt;
&lt;li&gt;&lt;p&gt;&lt;em&gt;The same folder will also be mapped as a volume to the &lt;strong&gt;./myp_dev/source/&lt;/strong&gt; folder of the host user account  (configured via the &lt;strong&gt;docker-compose.yml&lt;/strong&gt;).&lt;/em&gt;&lt;br&gt;
&lt;/p&gt;&lt;/li&gt;
&lt;/ul&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight plaintext"&gt;&lt;code&gt;EXPOSE 4000/tcp
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;ul&gt;
&lt;li&gt;
&lt;em&gt;This allows the default Phoenix web server port to be  mapped to a known port number of the host machine.  Precisely which port number is configured in the &lt;strong&gt;docker-compose.yml&lt;/strong&gt;.&lt;/em&gt;
&lt;/li&gt;
&lt;/ul&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight plaintext"&gt;&lt;code&gt;CMD sleep 50000
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;ul&gt;
&lt;li&gt;&lt;em&gt;Once a container runs, it wants to run to completion and  then shutdown in an orderly fashion.  We need it to hang  around so we can attach a console and carry out our  development work!&lt;/em&gt;&lt;/li&gt;
&lt;/ul&gt;

&lt;h2&gt;
  
  
  Remarks
&lt;/h2&gt;

&lt;ul&gt;
&lt;li&gt;An equivalent &lt;strong&gt;Dockerfile&lt;/strong&gt; based on Debian or Ubuntu can readily be put together.  Note however that the image will be near to twice the size(!).&lt;/li&gt;
&lt;li&gt;The &lt;strong&gt;inotify-tools&lt;/strong&gt; capability will pick up changes originating inside the container, but may not notice changes originating outside the container (e.g. your IDE). It does however need to be present as Phoenix squeals if it isn't.&lt;/li&gt;
&lt;/ul&gt;

</description>
      <category>docker</category>
      <category>elixir</category>
      <category>phoenix</category>
      <category>postgres</category>
    </item>
    <item>
      <title>Dockerizing Phoenix Development (3) PostgreSQL + PostGIS</title>
      <dc:creator>Alastair Measures</dc:creator>
      <pubDate>Sun, 30 May 2021 18:47:49 +0000</pubDate>
      <link>https://dev.to/alastairmeasures/dockerizing-phoenix-development-step-3-postgresql-postgis-ld1</link>
      <guid>https://dev.to/alastairmeasures/dockerizing-phoenix-development-step-3-postgresql-postgis-ld1</guid>
      <description>&lt;p&gt;This part is intended to pull together a running &lt;strong&gt;PostgreSQL&lt;/strong&gt; DBMS, with the &lt;strong&gt;PostGIS&lt;/strong&gt; extensions on hand, as a container co-ordinated by &lt;strong&gt;docker-compose&lt;/strong&gt;.&lt;/p&gt;

&lt;h2&gt;
  
  
  Approach
&lt;/h2&gt;

&lt;p&gt;This involves these parts:&lt;/p&gt;

&lt;ul&gt;
&lt;li&gt;Selecting an image from Docker Hub,&lt;/li&gt;
&lt;li&gt;Figuring out settings for this database image,&lt;/li&gt;
&lt;li&gt;Assembling a 'docker-compose.yml' file&lt;/li&gt;
&lt;li&gt;Run the container via 'docker-compose'

&lt;ul&gt;
&lt;li&gt;Establish a database instance &amp;amp; grant permissions&lt;/li&gt;
&lt;li&gt;Install PostGIS into a separate SQL schema&lt;/li&gt;
&lt;/ul&gt;


&lt;/li&gt;

&lt;/ul&gt;

&lt;h2&gt;
  
  
  Selecting an image from Docker Hub
&lt;/h2&gt;

&lt;p&gt;Visit &lt;a href="https://hub.docker.com" rel="noopener noreferrer"&gt;https://hub.docker.com&lt;/a&gt; and look around for a reasonable PostgreSQL image that includes &lt;a href="https://hub.docker.com/_/postgis/postgis" rel="noopener noreferrer"&gt;PostGIS&lt;/a&gt; extensions.  One choice that is current (June 2022): &lt;a href="https://hub.docker.com/_/postgis/postgis" rel="noopener noreferrer"&gt;postgis/postgis:14-3.2-alpine&lt;/a&gt;. &lt;/p&gt;

&lt;p&gt;If you really don't want or need PostGIS extensions, you could use: &lt;a href="https://hub.docker.com/_/postgres/postgres" rel="noopener noreferrer"&gt;postgres/postgres:14-alpine&lt;/a&gt;&lt;/p&gt;

&lt;h2&gt;
  
  
  Figuring out settings for database image
&lt;/h2&gt;

&lt;p&gt;&lt;a href="https://registry.hub.docker.com/_/postgres/" rel="noopener noreferrer"&gt;https://registry.hub.docker.com/_/postgres/&lt;/a&gt; provides good documentation, in the &lt;strong&gt;‘Overview’&lt;/strong&gt; tab, and allows you to look at the &lt;strong&gt;Dockerfile&lt;/strong&gt; that generated the &lt;strong&gt;postgis&lt;/strong&gt; image. &lt;/p&gt;

&lt;h2&gt;
  
  
  Assembling a 'docker-compose.yml' file
&lt;/h2&gt;

&lt;p&gt;This version will be extended in a later part of this series to include the Phoenix web server container.&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"

volumes:
  postgis14_data:

services:

  db:
    image: postgis/postgis:14-3.2-alpine
    ports:
      - 5432:5432
    environment:
#     - POSTGRES_USER=postgres
      - POSTGRES_PASSWORD=postgres
#     - POSTGRES_DB=postgres
    volumes:
      - postgis14_data:/var/lib/postgresql/data/
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;ul&gt;
&lt;li&gt;
&lt;em&gt;Note: the port 5432 being exposed allows access from tools on the host machine such as, say, &lt;a href="https://www.beekeeperstudio.io/" rel="noopener noreferrer"&gt;BeeKeeper Studio&lt;/a&gt;.&lt;/em&gt; &lt;/li&gt;
&lt;/ul&gt;

&lt;h2&gt;
  
  
  Run the container
&lt;/h2&gt;



&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight shell"&gt;&lt;code&gt;docker-compose  up  &lt;span class="nt"&gt;-d&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;ul&gt;
&lt;li&gt;&lt;em&gt;Note the -d flag which detaches the action from the  terminal and lets you have the command prompt back.&lt;/em&gt;&lt;/li&gt;
&lt;/ul&gt;

&lt;h3&gt;
  
  
  Establish a fresh database instance &amp;amp; grant permissions
&lt;/h3&gt;

&lt;p&gt;&lt;strong&gt;Connect to container as 'root' user:&lt;/strong&gt;&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight shell"&gt;&lt;code&gt;docker  &lt;span class="nb"&gt;exec&lt;/span&gt;  &lt;span class="nt"&gt;-it&lt;/span&gt; myp_dev_db_1  /bin/ash
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;ul&gt;
&lt;li&gt;&lt;p&gt;You should now have a shell prompt within the container.&lt;/p&gt;&lt;/li&gt;
&lt;li&gt;&lt;p&gt;&lt;em&gt;Note the use of 'ash' command shell rather than the 'bash' command shell.&lt;/em&gt; &lt;/p&gt;&lt;/li&gt;
&lt;/ul&gt;

&lt;p&gt;&lt;strong&gt;Within the container go into 'psql' as 'postgres':&lt;/strong&gt;&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight plaintext"&gt;&lt;code&gt;psql   -h localhost   -d postgres   -U postgres
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;ul&gt;
&lt;li&gt;&lt;em&gt;You should now have a SQL command prompt.&lt;/em&gt;&lt;/li&gt;
&lt;/ul&gt;

&lt;p&gt;&lt;strong&gt;Create a fresh user and database instance for development:&lt;/strong&gt;&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight sql"&gt;&lt;code&gt;&lt;span class="k"&gt;CREATE&lt;/span&gt; &lt;span class="k"&gt;USER&lt;/span&gt; &lt;span class="n"&gt;myp_user&lt;/span&gt; &lt;span class="k"&gt;WITH&lt;/span&gt; &lt;span class="k"&gt;ENCRYPTED&lt;/span&gt; &lt;span class="n"&gt;PASSWORD&lt;/span&gt; &lt;span class="s1"&gt;'Drowssap1'&lt;/span&gt; &lt;span class="p"&gt;;&lt;/span&gt;
&lt;span class="k"&gt;CREATE&lt;/span&gt; &lt;span class="k"&gt;DATABASE&lt;/span&gt; &lt;span class="n"&gt;myp_dev&lt;/span&gt; &lt;span class="p"&gt;;&lt;/span&gt;
&lt;span class="k"&gt;GRANT&lt;/span&gt; &lt;span class="k"&gt;ALL&lt;/span&gt; &lt;span class="k"&gt;PRIVILEGES&lt;/span&gt; &lt;span class="k"&gt;ON&lt;/span&gt; &lt;span class="k"&gt;DATABASE&lt;/span&gt; &lt;span class="n"&gt;myp_dev&lt;/span&gt; &lt;span class="k"&gt;TO&lt;/span&gt; &lt;span class="n"&gt;postgres&lt;/span&gt; &lt;span class="p"&gt;;&lt;/span&gt;
&lt;span class="err"&gt;\&lt;/span&gt;&lt;span class="n"&gt;q&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;ul&gt;
&lt;li&gt;&lt;em&gt;Note: On some GUI tools: if you try to paste these statements in together, they will be handled as a transaction which will then fail/ rollback from part way.  So probably best to do these statements one at a time!&lt;/em&gt;&lt;/li&gt;
&lt;/ul&gt;

&lt;h3&gt;
  
  
  Enable PostGIS into a separate SQL schema
&lt;/h3&gt;

&lt;p&gt;&lt;strong&gt;Connect into 'myp_dev' database as 'postgres':&lt;/strong&gt;&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight plaintext"&gt;&lt;code&gt;psql   -h localhost   -d myp_dev   -U postgres
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;ul&gt;
&lt;li&gt;&lt;em&gt;You should have a SQL command program at this point.&lt;/em&gt;&lt;/li&gt;
&lt;/ul&gt;

&lt;p&gt;&lt;strong&gt;Establish the 'postgis' extension into it's own SQL schema:&lt;/strong&gt;&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight sql"&gt;&lt;code&gt;&lt;span class="k"&gt;CREATE&lt;/span&gt; &lt;span class="k"&gt;SCHEMA&lt;/span&gt; &lt;span class="n"&gt;postgis&lt;/span&gt; &lt;span class="p"&gt;;&lt;/span&gt;
&lt;span class="k"&gt;ALTER&lt;/span&gt; &lt;span class="k"&gt;DATABASE&lt;/span&gt; &lt;span class="n"&gt;myp_dev&lt;/span&gt; &lt;span class="k"&gt;SET&lt;/span&gt; &lt;span class="n"&gt;search_path&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="n"&gt;postgis&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;&lt;span class="k"&gt;public&lt;/span&gt; &lt;span class="p"&gt;;&lt;/span&gt;
&lt;span class="err"&gt;\&lt;/span&gt;&lt;span class="n"&gt;q&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;Re enter database for changed &lt;strong&gt;search_path&lt;/strong&gt; to take effect:&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight sql"&gt;&lt;code&gt;&lt;span class="k"&gt;CREATE&lt;/span&gt; &lt;span class="n"&gt;EXTENSION&lt;/span&gt; &lt;span class="n"&gt;postgis&lt;/span&gt;&lt;span class="p"&gt;;&lt;/span&gt;
&lt;span class="k"&gt;ALTER&lt;/span&gt; &lt;span class="k"&gt;DATABASE&lt;/span&gt; &lt;span class="n"&gt;myp_dev&lt;/span&gt; &lt;span class="k"&gt;SET&lt;/span&gt; &lt;span class="n"&gt;search_path&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="k"&gt;public&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;&lt;span class="n"&gt;postgis&lt;/span&gt; &lt;span class="p"&gt;;&lt;/span&gt;
&lt;span class="err"&gt;\&lt;/span&gt;&lt;span class="n"&gt;q&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;ul&gt;
&lt;li&gt;
&lt;em&gt;Note that 'postgis' items are installed into the first schema in the &lt;strong&gt;'search_path'&lt;/strong&gt;.&lt;/em&gt; &lt;/li&gt;
&lt;li&gt;
&lt;em&gt;There are further PostGIS related extensions - see &lt;a href="https://www.postgis.net" rel="noopener noreferrer"&gt;https://www.postgis.net&lt;/a&gt; for more details.&lt;/em&gt; &lt;/li&gt;
&lt;/ul&gt;

&lt;h2&gt;
  
  
  Close things
&lt;/h2&gt;

&lt;p&gt;&lt;strong&gt;Drop the container command line:&lt;/strong&gt;&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight plaintext"&gt;&lt;code&gt;exit
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;&lt;strong&gt;Shutdown the running container from the host command line:&lt;/strong&gt;&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight plaintext"&gt;&lt;code&gt;docker-compose  down
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;ul&gt;
&lt;li&gt;&lt;em&gt;Note this needs you to be in the same folder as when the 'up' command was  issued.&lt;/em&gt;&lt;/li&gt;
&lt;/ul&gt;

&lt;h2&gt;
  
  
  Remarks
&lt;/h2&gt;

&lt;ul&gt;
&lt;li&gt;This setup is for &lt;strong&gt;development only&lt;/strong&gt;; testing and deployment will each be different.&lt;/li&gt;
&lt;li&gt;Some would develop while working as the 'postgres' user  (with postgres administrator rights), and it can be convenient.  Although everything here is within a sandbox (aka container): developing as 'root' user or database administrator is avoided as being bad practice. &lt;/li&gt;
&lt;li&gt;Good practice here includes ensuring that the 'postgis' tables, indexes, functions, etc are created into their own SQL schema rather than being mixed in with the rest of your application tables. &lt;/li&gt;
&lt;li&gt;Docker-compose does some automated naming of containers, networks and volumes that seems really intuitive and useful!&lt;/li&gt;
&lt;/ul&gt;

</description>
      <category>docker</category>
      <category>elixir</category>
      <category>phoenix</category>
      <category>postgres</category>
    </item>
    <item>
      <title>Dockerizing Phoenix Development (2) Folders &amp; Files</title>
      <dc:creator>Alastair Measures</dc:creator>
      <pubDate>Sun, 30 May 2021 18:45:42 +0000</pubDate>
      <link>https://dev.to/alastairmeasures/dockerizing-phoenix-development-step-2-folders-files-el4</link>
      <guid>https://dev.to/alastairmeasures/dockerizing-phoenix-development-step-2-folders-files-el4</guid>
      <description>&lt;p&gt;The overall objective is to construct a development environment within Docker for a website based on &lt;a href="https://www.phoenixframework.org/" rel="noopener noreferrer"&gt;Phoenix&lt;/a&gt; and &lt;a href="https://elixir-lang.org/" rel="noopener noreferrer"&gt;Elixir&lt;/a&gt; backed by &lt;a href="https://www.postgresql.org/" rel="noopener noreferrer"&gt;PostgreSQL&lt;/a&gt; with &lt;a href="https://www.postgis.net/" rel="noopener noreferrer"&gt;PostGIS&lt;/a&gt;.&lt;/p&gt;

&lt;p&gt;We are working through &lt;strong&gt;'docker-compose'&lt;/strong&gt;, with project parameters in an explicit, indented YAML file rather than a bash script.&lt;/p&gt;

&lt;p&gt;This step is intended to set out the organisation of files and folders being used, and explain each.&lt;/p&gt;

&lt;h2&gt;
  
  
  Hierarchy
&lt;/h2&gt;

&lt;ul&gt;
&lt;li&gt;./base_folder/ &lt;em&gt;(folder - might be $HOME)&lt;/em&gt;

&lt;ul&gt;
&lt;li&gt;/myp_dev/ &lt;em&gt;(folder of entire project)&lt;/em&gt;

&lt;ul&gt;
&lt;li&gt;/docker-compose.yml &lt;em&gt;(text file scripting images to run together)&lt;/em&gt;
&lt;/li&gt;
&lt;li&gt;/Dockerfile.alpine &lt;em&gt;(text file defining image for web server)&lt;/em&gt;
&lt;/li&gt;
&lt;li&gt;/source/ &lt;em&gt;(folder where your Elixir code goes)&lt;/em&gt;
&lt;/li&gt;
&lt;/ul&gt;


&lt;/li&gt;

&lt;/ul&gt;

&lt;/li&gt;

&lt;/ul&gt;

&lt;h3&gt;
  
  
  ./myp_dev
&lt;/h3&gt;

&lt;ul&gt;
&lt;li&gt;&lt;p&gt;This is a folder that encapsulates our whole exercise.  The docker-compose commands should be issued from this folder.&lt;/p&gt;&lt;/li&gt;
&lt;li&gt;&lt;p&gt;&lt;em&gt;Note: when docker-compose starts our collection of containers: it names them  including this folder name as a prefix.  This feature is helpful and makes it easier to run, say, a beta version alongside a development version for comparison purposes.&lt;/em&gt;&lt;/p&gt;&lt;/li&gt;
&lt;/ul&gt;

&lt;h3&gt;
  
  
  ./myp_dev/docker-compose.yml
&lt;/h3&gt;

&lt;ul&gt;
&lt;li&gt;This is a text file; which scripts the necessary images required to bring up a group of containers as a system.&lt;/li&gt;
&lt;/ul&gt;

&lt;h3&gt;
  
  
  ./myp_dev/Dockerfile.alpine
&lt;/h3&gt;

&lt;ul&gt;
&lt;li&gt;This is a text file, we use to build an image for Elixir and Phoenix.&lt;/li&gt;
&lt;/ul&gt;

&lt;h3&gt;
  
  
  ./myp_dev/source
&lt;/h3&gt;

&lt;ul&gt;
&lt;li&gt;This folder will contain all our Elixir and Phoenix coding. This folder will be mounted as a volume into the container. In this way we can run our web server inside the container, and, at the same time, use editors and IDE software on the host system (from outside the container).&lt;/li&gt;
&lt;/ul&gt;

&lt;h2&gt;
  
  
  Remarks
&lt;/h2&gt;

&lt;ul&gt;
&lt;li&gt;&lt;p&gt;&lt;em&gt;By default: the user inside the container is &lt;strong&gt;'root'&lt;/strong&gt; (&lt;em&gt;for that container&lt;/em&gt;) and will not let you edit files created if you are anything less!&lt;/em&gt;&lt;/p&gt;&lt;/li&gt;
&lt;li&gt;&lt;p&gt;&lt;em&gt;To make this work smoothly, the &lt;strong&gt;'user id'&lt;/strong&gt; and &lt;strong&gt;'group id'&lt;/strong&gt; used for development within the container &lt;strong&gt;will need&lt;/strong&gt; to match those of the development user on the host machine.&lt;/em&gt; &lt;/p&gt;&lt;/li&gt;
&lt;li&gt;&lt;p&gt;&lt;em&gt;This exercise has been assembled under Linux and will very  probably work hosted on a Mac.  Windows, however, formats   text files differently and trying to use the same folders   from a container (Linux) and the host (Windows) is likely   to give you gremlins!  (End of line and end of file are coded differently).  Some IDE software such as &lt;a href="https://www.activestate.com/products/komodo-ide/" rel="noopener noreferrer"&gt;KomodoIDE&lt;/a&gt; may have preference settings that help, however it remains a courageous practice.&lt;/em&gt;&lt;/p&gt;&lt;/li&gt;
&lt;/ul&gt;

</description>
      <category>docker</category>
      <category>elixir</category>
      <category>phoenix</category>
      <category>postgres</category>
    </item>
    <item>
      <title>Dockerizing Phoenix Development (1) Introduction</title>
      <dc:creator>Alastair Measures</dc:creator>
      <pubDate>Sun, 30 May 2021 18:45:22 +0000</pubDate>
      <link>https://dev.to/alastairmeasures/dockerizing-phoenix-development-step-1-introduction-377i</link>
      <guid>https://dev.to/alastairmeasures/dockerizing-phoenix-development-step-1-introduction-377i</guid>
      <description>&lt;p&gt;The overall objective here is to construct a development environment within &lt;a href="https://www.docker.com" rel="noopener noreferrer"&gt;Docker&lt;/a&gt; for a website based on: &lt;a href="https://www.phoenixframework.org/" rel="noopener noreferrer"&gt;Phoenix&lt;/a&gt; and &lt;a href="https://elixir-lang.org/" rel="noopener noreferrer"&gt;Elixir&lt;/a&gt; backed by &lt;a href="https://www.postgresql.org/" rel="noopener noreferrer"&gt;PostgreSQL&lt;/a&gt; with &lt;a href="https://www.postgis.net/" rel="noopener noreferrer"&gt;PostGIS&lt;/a&gt;.&lt;/p&gt;

&lt;p&gt;The plan is to have the Elixir and Phoenix work entirely within the container, even allowing projects to be started from scratch;  thereby removing the need to have Elixir and Phoenix installed on the host machine.&lt;/p&gt;

&lt;p&gt;The intention here is that these steps will get a relative newcomer up and running: with some understanding. It is written to be relatively gentle on the reader, if a bit slow for some.&lt;/p&gt;

&lt;blockquote&gt;
&lt;p&gt;For those not yet familiar: &lt;a href="https://www.postgis.net/" rel="noopener noreferrer"&gt;PostGIS&lt;/a&gt; is a group of extensions for &lt;a href="https://www.postgresql.org/" rel="noopener noreferrer"&gt;PostgreSQL&lt;/a&gt; which include geographical capabilities that are both sophisticated and  &lt;a href="https://www.ogc.org/" rel="noopener noreferrer"&gt;standards compliant&lt;/a&gt; .&lt;/p&gt;
&lt;/blockquote&gt;

&lt;h2&gt;
  
  
  Approach
&lt;/h2&gt;

&lt;p&gt;Using Docker so that the project:&lt;/p&gt;

&lt;ul&gt;
&lt;li&gt;can be reproduced on demand for colleagues or others.&lt;/li&gt;
&lt;li&gt;is largely prepared for deployment through Docker.&lt;/li&gt;
&lt;li&gt;can co-exist with other projects using different version permutations.&lt;/li&gt;
&lt;/ul&gt;

&lt;p&gt;Choosing/ constructing Docker images so that they are lean and targetted to the purpose in hand.&lt;/p&gt;

&lt;p&gt;To enable IDEs and other tools (on the host machine) to work with source code inside a container.&lt;/p&gt;

&lt;p&gt;Using &lt;strong&gt;'docker-compose'&lt;/strong&gt; so that parameters are scripted in the YAML format for clarity and simplicity.&lt;/p&gt;

&lt;h2&gt;
  
  
  Prerequisites and Platforms
&lt;/h2&gt;

&lt;p&gt;This exercise was constructed and tested on the following platform:&lt;/p&gt;

&lt;ul&gt;
&lt;li&gt;&lt;p&gt;&lt;a href="https://ubuntu.com/#download" rel="noopener noreferrer"&gt;Ubuntu 20.04 LTS&lt;/a&gt; with  &lt;a href="https://docs.docker.com/engine/installation" rel="noopener noreferrer"&gt;Docker&lt;/a&gt; and  &lt;a href="https://docs.docker.com/engine/install/linux-postinstall/" rel="noopener noreferrer"&gt;Docker Compose&lt;/a&gt;.&lt;/p&gt;&lt;/li&gt;
&lt;li&gt;&lt;p&gt;There are a couple of ways of installing &lt;strong&gt;docker&lt;/strong&gt; on Ubuntu; the recommended one is &lt;a href="https://docs.docker.com/engine/install/ubuntu/" rel="noopener noreferrer"&gt;documented on the Docker website&lt;/a&gt;&lt;/p&gt;&lt;/li&gt;
&lt;li&gt;&lt;p&gt;Reproducing this exercise should work just fine on Linux and Mac platforms. &lt;em&gt;Windows however, would be tricky for reasons explained in step 2&lt;/em&gt;.&lt;/p&gt;&lt;/li&gt;
&lt;/ul&gt;

&lt;h2&gt;
  
  
  Recommended Extras
&lt;/h2&gt;

&lt;ul&gt;
&lt;li&gt;&lt;p&gt;It is good to have a graphical view into what is going on  within the docker server.  Installing &lt;a href="https://www.portainer.io" rel="noopener noreferrer"&gt;Portainer Community Edition&lt;/a&gt; as a container is a good option, allowing interaction through a browser.&lt;/p&gt;&lt;/li&gt;
&lt;li&gt;&lt;p&gt;Given that a database is involved it is also good to have  a GUI based SQL tool on hand.  &lt;a href="https://www.beekeeperstudio.io/" rel="noopener noreferrer"&gt;BeeKeeper Studio&lt;/a&gt; is one option (also available among the snap applications on Ubuntu).&lt;/p&gt;&lt;/li&gt;
&lt;/ul&gt;

&lt;h2&gt;
  
  
  Remarks
&lt;/h2&gt;

&lt;ul&gt;
&lt;li&gt;&lt;p&gt;&lt;em&gt;This overall exercise reflects lessons learned the hard way by the author - a journey that took time.  This route works; however there may be better techniques - it is humbly requested that such wisdom is shared constructively in the comments.&lt;/em&gt;&lt;/p&gt;&lt;/li&gt;
&lt;li&gt;&lt;p&gt;&lt;em&gt;You are expected to use this as a kind of template.  Use your own project acronym, use later editions of PostgreSQL, PostGIS, Elixir and/ or Phoenix; as you need.&lt;/em&gt;&lt;/p&gt;&lt;/li&gt;
&lt;li&gt;&lt;p&gt;&lt;em&gt;If you don't need PostGIS: you can either leave it in or figure out which parts to adjust as you go through.&lt;/em&gt;&lt;/p&gt;&lt;/li&gt;
&lt;/ul&gt;

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