<?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: Julien LEICHER</title>
    <description>The latest articles on DEV Community by Julien LEICHER (@yuukanoo).</description>
    <link>https://dev.to/yuukanoo</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%2F559437%2F6a85c13d-7b20-4a02-95be-a25c5c9096f9.jpeg</url>
      <title>DEV Community: Julien LEICHER</title>
      <link>https://dev.to/yuukanoo</link>
    </image>
    <atom:link rel="self" type="application/rss+xml" href="https://dev.to/feed/yuukanoo"/>
    <language>en</language>
    <item>
      <title>Containerizing and deploying a Go application with seelf</title>
      <dc:creator>Julien LEICHER</dc:creator>
      <pubDate>Mon, 05 Jun 2023 09:27:11 +0000</pubDate>
      <link>https://dev.to/yuukanoo/containerizing-and-deploying-a-go-application-with-seelf-1dpj</link>
      <guid>https://dev.to/yuukanoo/containerizing-and-deploying-a-go-application-with-seelf-1dpj</guid>
      <description>&lt;p&gt;Going from a locally running project to a remote deployment available to users can sometimes feel frustrating, especially if your needs are simple.&lt;/p&gt;

&lt;p&gt;Today, I'll show you how you can take a tiny Golang application, containerize it using a &lt;code&gt;Dockerfile&lt;/code&gt; and a &lt;code&gt;compose.yml&lt;/code&gt; file, and deploy it without frustration using a tiny open-source project I've made: &lt;a href="https://github.com/YuukanOO/seelf"&gt;seelf&lt;/a&gt;.&lt;/p&gt;

&lt;h2&gt;
  
  
  First things first, our toy application
&lt;/h2&gt;

&lt;p&gt;So you're a developer and you came up with a fantastic application idea: a tiny Golang application with outputs the number of times it has been started. To make things interesting, you also had decided to logs the application start time in a PostgreSQL database.&lt;/p&gt;

&lt;p&gt;&lt;em&gt;Note: This application is available at: &lt;a href="https://github.com/YuukanOO/seelf-go-tutorial"&gt;https://github.com/YuukanOO/seelf-go-tutorial&lt;/a&gt; and each step has its own branch.&lt;/em&gt;&lt;/p&gt;

&lt;p&gt;So you make this application, runs it locally with an instance of PostgreSQL and everything is fine, you're proud of you (and you should always be)!&lt;/p&gt;

&lt;h2&gt;
  
  
  Here comes Docker
&lt;/h2&gt;

&lt;p&gt;As you know containerizing an application is a great way to deploy and share it easily, you come up with this &lt;code&gt;Dockerfile&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;FROM golang:1.20-alpine AS builder
WORKDIR /app
COPY go.* ./
RUN go mod download
COPY . .
RUN go build -ldflags="-s -w" -o sample

FROM alpine:3.16
WORKDIR /app
COPY --from=builder /app/sample ./
EXPOSE 8080
CMD ["./sample"]
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;And a &lt;code&gt;compose.yml&lt;/code&gt; file to launch all your application stack in one command:&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;services&lt;/span&gt;&lt;span class="pi"&gt;:&lt;/span&gt;
  &lt;span class="na"&gt;app&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="s"&gt;.&lt;/span&gt;
    &lt;span class="na"&gt;restart&lt;/span&gt;&lt;span class="pi"&gt;:&lt;/span&gt; &lt;span class="s"&gt;unless-stopped&lt;/span&gt;
    &lt;span class="na"&gt;environment&lt;/span&gt;&lt;span class="pi"&gt;:&lt;/span&gt;
      &lt;span class="pi"&gt;-&lt;/span&gt; &lt;span class="s"&gt;DATABASE_URL=postgresql://dbuser:dbpass@db:5432/sample?sslmode=disable&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="s"&gt;8080:8080&lt;/span&gt;
    &lt;span class="na"&gt;depends_on&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;condition&lt;/span&gt;&lt;span class="pi"&gt;:&lt;/span&gt; &lt;span class="s"&gt;service_healthy&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="s"&gt;postgres:15-alpine&lt;/span&gt;
    &lt;span class="na"&gt;restart&lt;/span&gt;&lt;span class="pi"&gt;:&lt;/span&gt; &lt;span class="s"&gt;unless-stopped&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;dbuser&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;dbpass&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;sample&lt;/span&gt;
    &lt;span class="na"&gt;healthcheck&lt;/span&gt;&lt;span class="pi"&gt;:&lt;/span&gt;
      &lt;span class="na"&gt;test&lt;/span&gt;&lt;span class="pi"&gt;:&lt;/span&gt; &lt;span class="s"&gt;pg_isready -d $${POSTGRES_DB} -U $${POSTGRES_USER}&lt;/span&gt;
      &lt;span class="na"&gt;interval&lt;/span&gt;&lt;span class="pi"&gt;:&lt;/span&gt; &lt;span class="s"&gt;5s&lt;/span&gt;
      &lt;span class="na"&gt;timeout&lt;/span&gt;&lt;span class="pi"&gt;:&lt;/span&gt; &lt;span class="s"&gt;5s&lt;/span&gt;
      &lt;span class="na"&gt;retries&lt;/span&gt;&lt;span class="pi"&gt;:&lt;/span&gt; &lt;span class="m"&gt;5&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;dbdata:/var/lib/postgresql/data&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;dbdata&lt;/span&gt;&lt;span class="pi"&gt;:&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;Now, you can run &lt;code&gt;docker compose up -d --wait --build&lt;/code&gt; and your application is available at &lt;a href="http://localhost:8080"&gt;http://localhost:8080&lt;/a&gt;.&lt;/p&gt;

&lt;h2&gt;
  
  
  Going live with seelf
&lt;/h2&gt;

&lt;p&gt;And now, you really want to share this amazing app with the world. Since you really like self-hosting, you have deployed &lt;a href="https://github.com/YuukanOO/seelf/blob/main/DOCUMENTATION.md#installation"&gt;seelf&lt;/a&gt; on a tiny VPS.&lt;/p&gt;

&lt;p&gt;seelf is a &lt;strong&gt;lightweight self-hosting deployment&lt;/strong&gt; platform written in &lt;strong&gt;Go&lt;/strong&gt; which takes a compose file and deploy an application stack, exposing services at nice URLs and managing certificates so you don't have to.&lt;/p&gt;

&lt;p&gt;So you start by creating an application on your seelf instance by clicking on the &lt;em&gt;New application&lt;/em&gt; button.&lt;/p&gt;

&lt;p&gt;&lt;a href="https://res.cloudinary.com/practicaldev/image/fetch/s--L3TyPD7k--/c_limit%2Cf_auto%2Cfl_progressive%2Cq_auto%2Cw_800/https://dev-to-uploads.s3.amazonaws.com/uploads/articles/ycphz3qfhw3loe98iqu7.png" class="article-body-image-wrapper"&gt;&lt;img src="https://res.cloudinary.com/practicaldev/image/fetch/s--L3TyPD7k--/c_limit%2Cf_auto%2Cfl_progressive%2Cq_auto%2Cw_800/https://dev-to-uploads.s3.amazonaws.com/uploads/articles/ycphz3qfhw3loe98iqu7.png" alt="seelf homepage" width="800" height="662"&gt;&lt;/a&gt;&lt;/p&gt;

&lt;p&gt;You fill the provided form with a nice name for your application (as this will determine the subdomain used), the git repository url, and set production environment variables for the &lt;code&gt;app&lt;/code&gt; and &lt;code&gt;db&lt;/code&gt; services which will overwrite the default ones defined in the &lt;code&gt;compose.yml&lt;/code&gt; file.&lt;/p&gt;

&lt;p&gt;&lt;a href="https://res.cloudinary.com/practicaldev/image/fetch/s--rx3Y2rml--/c_limit%2Cf_auto%2Cfl_progressive%2Cq_auto%2Cw_800/https://dev-to-uploads.s3.amazonaws.com/uploads/articles/jpgk8if6a4hbrb7pz0i3.png" class="article-body-image-wrapper"&gt;&lt;img src="https://res.cloudinary.com/practicaldev/image/fetch/s--rx3Y2rml--/c_limit%2Cf_auto%2Cfl_progressive%2Cq_auto%2Cw_800/https://dev-to-uploads.s3.amazonaws.com/uploads/articles/jpgk8if6a4hbrb7pz0i3.png" alt="seelf new application form" width="800" height="1328"&gt;&lt;/a&gt;&lt;/p&gt;

&lt;p&gt;You click &lt;em&gt;Create&lt;/em&gt; and on the next screen, the &lt;em&gt;New deployment&lt;/em&gt; button will ask you what kind of deployment you want to trigger for your newly created application.&lt;/p&gt;

&lt;p&gt;&lt;a href="https://res.cloudinary.com/practicaldev/image/fetch/s--Aagn5ENj--/c_limit%2Cf_auto%2Cfl_progressive%2Cq_auto%2Cw_800/https://dev-to-uploads.s3.amazonaws.com/uploads/articles/npss7te82gtqz6mwf2d6.png" class="article-body-image-wrapper"&gt;&lt;img src="https://res.cloudinary.com/practicaldev/image/fetch/s--Aagn5ENj--/c_limit%2Cf_auto%2Cfl_progressive%2Cq_auto%2Cw_800/https://dev-to-uploads.s3.amazonaws.com/uploads/articles/npss7te82gtqz6mwf2d6.png" alt="seelf new deployment page" width="800" height="662"&gt;&lt;/a&gt;&lt;/p&gt;

&lt;p&gt;You choose &lt;code&gt;git&lt;/code&gt; as the deployment kind since your application is hosted on &lt;a href="https://github.com/YuukanOO/seelf-go-tutorial/tree/containerizing"&gt;github&lt;/a&gt; and enter the branch you want to deploy (&lt;code&gt;containerizing&lt;/code&gt; in this example).&lt;/p&gt;

&lt;p&gt;After a few seconds, the deployment should be complete and your application available.&lt;/p&gt;

&lt;p&gt;&lt;a href="https://res.cloudinary.com/practicaldev/image/fetch/s--8Fjnfvnz--/c_limit%2Cf_auto%2Cfl_progressive%2Cq_auto%2Cw_800/https://dev-to-uploads.s3.amazonaws.com/uploads/articles/9hspsnlzn39gc0asqhiu.png" class="article-body-image-wrapper"&gt;&lt;img src="https://res.cloudinary.com/practicaldev/image/fetch/s--8Fjnfvnz--/c_limit%2Cf_auto%2Cfl_progressive%2Cq_auto%2Cw_800/https://dev-to-uploads.s3.amazonaws.com/uploads/articles/9hspsnlzn39gc0asqhiu.png" alt="seelf successful deployment" width="800" height="743"&gt;&lt;/a&gt;&lt;/p&gt;

&lt;p&gt;Clicking the &lt;code&gt;app&lt;/code&gt; link in the &lt;em&gt;deployed services&lt;/em&gt; section of the deployment will open a new page to your live application!&lt;/p&gt;

&lt;p&gt;&lt;a href="https://res.cloudinary.com/practicaldev/image/fetch/s--t8FIFzKc--/c_limit%2Cf_auto%2Cfl_progressive%2Cq_auto%2Cw_800/https://dev-to-uploads.s3.amazonaws.com/uploads/articles/1gfdgm536c4is4luzrit.png" class="article-body-image-wrapper"&gt;&lt;img src="https://res.cloudinary.com/practicaldev/image/fetch/s--t8FIFzKc--/c_limit%2Cf_auto%2Cfl_progressive%2Cq_auto%2Cw_800/https://dev-to-uploads.s3.amazonaws.com/uploads/articles/1gfdgm536c4is4luzrit.png" alt="your application is live" width="800" height="145"&gt;&lt;/a&gt;&lt;/p&gt;

&lt;p&gt;Congratulations, you have successfuly deployed your first application with &lt;strong&gt;seelf&lt;/strong&gt;!&lt;/p&gt;

&lt;p&gt;&lt;em&gt;seelf is in its early stage but you can check the &lt;a href="https://github.com/YuukanOO/seelf/milestone/1"&gt;roadmap&lt;/a&gt; to see what's planned. Thanks for taking the time to read this ;)&lt;/em&gt;&lt;/p&gt;

</description>
      <category>docker</category>
      <category>tutorial</category>
      <category>opensource</category>
      <category>go</category>
    </item>
  </channel>
</rss>
