<?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: Jon Friesen</title>
    <description>The latest articles on DEV Community by Jon Friesen (@jonfriesen).</description>
    <link>https://dev.to/jonfriesen</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%2F110961%2Fa183a763-8924-4f2a-ad4d-e7d38bb08546.jpg</url>
      <title>DEV Community: Jon Friesen</title>
      <link>https://dev.to/jonfriesen</link>
    </image>
    <atom:link rel="self" type="application/rss+xml" href="https://dev.to/feed/jonfriesen"/>
    <language>en</language>
    <item>
      <title>Review: Learn Concurrent Programming with Go</title>
      <dc:creator>Jon Friesen</dc:creator>
      <pubDate>Thu, 22 Feb 2024 00:00:00 +0000</pubDate>
      <link>https://dev.to/jonfriesen/review-learn-concurrent-programming-with-go-5384</link>
      <guid>https://dev.to/jonfriesen/review-learn-concurrent-programming-with-go-5384</guid>
      <description>&lt;p&gt;Go has been my primarily language for the last ~6 years, however, until now I’ve primarily been a consumer of libraries that employ high levels of concurrent programming and had minimal experience implementing these patterns on my own let alone in a production setting.&lt;/p&gt;

&lt;p&gt;I stumbled upon &lt;a href="https://www.manning.com/books/learn-concurrent-programming-with-go"&gt;Learn Concurrent Programming with Go&lt;/a&gt; in a &lt;a href="https://www.reddit.com/r/golang/comments/18b86aa/my_concurrent_programming_book_is_finally/"&gt;Reddit post&lt;/a&gt; by the author, &lt;a href="https://www.cutajarjames.com/"&gt;James Cutajar&lt;/a&gt; announcing it’s release.. My first impression was “that’s neat” and moved along with my daily reddit based procrastination routine before quickly scrolling back searching in earnest for as this is a skill I wanted to get better at.&lt;/p&gt;

&lt;p&gt;&lt;a href="https://res.cloudinary.com/practicaldev/image/fetch/s--FsYAUSt7--/c_limit%2Cf_auto%2Cfl_progressive%2Cq_auto%2Cw_800/https://jonfriesen.ca/_next/static/media/learn-concurrent-programming-with-go.77e18134.jpg" class="article-body-image-wrapper"&gt;&lt;img src="https://res.cloudinary.com/practicaldev/image/fetch/s--FsYAUSt7--/c_limit%2Cf_auto%2Cfl_progressive%2Cq_auto%2Cw_800/https://jonfriesen.ca/_next/static/media/learn-concurrent-programming-with-go.77e18134.jpg" alt="book cover photo" width="800" height="1003"&gt;&lt;/a&gt;&lt;/p&gt;

&lt;p&gt;James does a fantastic job of reviewing the foundational requirements for a developer, touching on concurrency topics like processes vs threads, and then dives into patterns using the Go standard library tooling to demonstrate these. Taking time to explain topics like communicating sequential processes (CSP) and then implementing variations of patterns described in CSP with Go.&lt;/p&gt;

&lt;p&gt;The book excels at keeping the density of information vs the pace of the book at a really consumable speed for your average developer. The strength of this books versus other sources on concurrency and concurrency with Go are that it really focuses on teaching the fundamental patterns with what’s going on under the hood; the lessons learned here are immediately applicable to Go programs, but even more so a skill that is transferrable to other languages, systems, and frameworks.&lt;/p&gt;

&lt;p&gt;The weakest part of Learn Concurrent Programming with Go is the cartoon diagrams which I found difficult to follow and ended up largely ignoring.&lt;/p&gt;

&lt;p&gt;Overall I’m super happy my purchase and would recommend this to Go developers early in their Go journey as it’s a great example of applying known concurrency patterns in Go, as well as experienced Gophers who want to brush up on their concurrency knowledge in a language they’re familiar with.&lt;/p&gt;

</description>
      <category>books</category>
      <category>go</category>
    </item>
    <item>
      <title>How to create GitHub Actions test summaries for Go</title>
      <dc:creator>Jon Friesen</dc:creator>
      <pubDate>Thu, 09 Nov 2023 00:00:00 +0000</pubDate>
      <link>https://dev.to/jonfriesen/how-to-create-github-actions-test-summaries-for-go-994</link>
      <guid>https://dev.to/jonfriesen/how-to-create-github-actions-test-summaries-for-go-994</guid>
      <description>&lt;p&gt;One of my pet peeves is searching CI output for test failure details. While I realize that in many cases this is a necessity, in &lt;em&gt;most&lt;/em&gt; cases I think this can be avoided using test output summaries. Luckily, there are two open source tools we can take advantage of to easily implement test summaries in GitHub Actions and Go tests.&lt;/p&gt;

&lt;p&gt;First we need to generate the test summary xml file. The tool I commonly use across my test running needs is &lt;a href="https://github.com/gotestyourself/gotestsum"&gt;gotestyourself/gotestsum&lt;/a&gt;. This is a great tool for grouped console outputs and generating nice junit xml outputs.&lt;/p&gt;

&lt;p&gt;Install with:&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight plaintext"&gt;&lt;code&gt;go install gotest.tools/gotestsum@latest

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

&lt;/div&gt;



&lt;p&gt;gotestsum is a drop-in replacement for &lt;code&gt;go test&lt;/code&gt;, so we can someone easily replace this in our GitHub Action workflow:&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight plaintext"&gt;&lt;code&gt;    - name: Test
    run: go run gotest.tools/gotestsum@latest --junitfile unit-tests.xml --format pkgname

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

&lt;/div&gt;



&lt;p&gt;This simple workflow step will run the tests in the current folder, grouping by package name, and save the summary to a unit-tests.xml file. In cases where there are different styles of tests, (eg. unit, integration, e2e) running this multiple type and creating sepearate junitfiles is helpful.&lt;/p&gt;

&lt;p&gt;Now we need to run our final step of persisting the test files as action summaries, to do this we will take advantage of the &lt;a href="https://github.com/test-summary/action"&gt;test-summary/action&lt;/a&gt; project. Added to our workflow file as:&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight plaintext"&gt;&lt;code&gt;    - name: Test Summary
    uses: test-summary/action@v2
    with:
        paths: "unit-tests.xml"
    if: always()

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

&lt;/div&gt;



&lt;p&gt;This step will persist the test summaries and make them accessible to GitHub Actions for display. Providing an output like:&lt;/p&gt;

&lt;p&gt;&lt;a href="https://res.cloudinary.com/practicaldev/image/fetch/s--J64E4F-l--/c_limit%2Cf_auto%2Cfl_progressive%2Cq_auto%2Cw_800/https://jonfriesen.ca/_next/static/media/test-summary.a6372ccf.png" class="article-body-image-wrapper"&gt;&lt;img src="https://res.cloudinary.com/practicaldev/image/fetch/s--J64E4F-l--/c_limit%2Cf_auto%2Cfl_progressive%2Cq_auto%2Cw_800/https://jonfriesen.ca/_next/static/media/test-summary.a6372ccf.png" alt="A screenshot of GitHub Actions build summary with test results." width="800" height="207"&gt;&lt;/a&gt;&lt;/p&gt;

&lt;h3&gt;
  
  
  Full Workflow Sample:
&lt;/h3&gt;



&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight plaintext"&gt;&lt;code&gt;name: build

on:
  push:
    branches:
      - main
  pull_request:
    branches:
      - main

jobs:
  build:
    runs-on: ubuntu-latest

    steps:
      - name: Set up Go 1.19
        uses: actions/setup-go@v1
        with:
          go-version: 1.19
        id: go

      - name: Check out code
        uses: actions/checkout@v1

      - name: Test
        run: go run gotest.tools/gotestsum@latest --junitfile unit-tests.xml --format pkgname

      - name: Test Summary
        uses: test-summary/action@v2
        with:
          paths: "unit-tests.xml"
        if: always()

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

&lt;/div&gt;



</description>
      <category>go</category>
      <category>githubactions</category>
    </item>
    <item>
      <title>Go Explored: new() vs make()</title>
      <dc:creator>Jon Friesen</dc:creator>
      <pubDate>Sat, 27 May 2023 00:00:00 +0000</pubDate>
      <link>https://dev.to/jonfriesen/go-explored-new-vs-make-4dg4</link>
      <guid>https://dev.to/jonfriesen/go-explored-new-vs-make-4dg4</guid>
      <description>&lt;p&gt;The Go standard library includes two built-in functions that are commonly used, though in many cases are not totally clear about what they are doing behind the scenes and why they are being used. They are &lt;code&gt;new()&lt;/code&gt; and &lt;code&gt;make()&lt;/code&gt;.&lt;/p&gt;

&lt;blockquote&gt;
&lt;p&gt;As a side note: this blog post is more of a reminder to myself about what these do.&lt;/p&gt;
&lt;/blockquote&gt;

&lt;h2&gt;
  
  
  The &lt;code&gt;new()&lt;/code&gt; function
&lt;/h2&gt;

&lt;p&gt;The &lt;code&gt;new()&lt;/code&gt; function can instantiate any struct or value data type. When new is called, Go will allocate the memory without initializing it. This means that the memory reserved is "zeroed". When new is called with a data type it will return a pointer to a zero value memory location of the type you've specified.&lt;/p&gt;

&lt;p&gt;Here's a simple example:&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight plaintext"&gt;&lt;code&gt;i := new(int)
fmt.Println(*i)
// prints: 0

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

&lt;/div&gt;



&lt;p&gt;In the above example &lt;code&gt;new(int)&lt;/code&gt; reserves space for an integer, initializes that space to zero, and returns a pointer to it. Like most Go variables, the space is released by the garbage collector when the pointer is no longer referenced.&lt;/p&gt;

&lt;h3&gt;
  
  
  Example
&lt;/h3&gt;

&lt;p&gt;&lt;code&gt;new()&lt;/code&gt; would be used when you want to allocated a zeroed value for the pointer it creates. This is useful when working with basic types or custom structs.&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight plaintext"&gt;&lt;code&gt;type Person struct {
    Name string
    Age int
}

p := new(Person)
fmt.Println(*p)
// prints: { 0}

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

&lt;/div&gt;



&lt;h2&gt;
  
  
  The &lt;code&gt;make()&lt;/code&gt; function
&lt;/h2&gt;

&lt;p&gt;&lt;code&gt;make()&lt;/code&gt; has a much tighter scope as it can only instantiate channels, maps, and slices and returns an initialized value (not a pointer) which is not zeroed. The data structure of the type is ready for use.&lt;/p&gt;

&lt;p&gt;Here's a simple example:&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight plaintext"&gt;&lt;code&gt;s := make([]int, 5)
fmt.Println(s)
// prints: [0 0 0 0 0]

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

&lt;/div&gt;



&lt;p&gt;In the above example &lt;code&gt;make([]int, 5)&lt;/code&gt; creates a slice of integers with a length of 5 where all elements within are initialized to zero.&lt;/p&gt;

&lt;h3&gt;
  
  
  Example
&lt;/h3&gt;

&lt;p&gt;&lt;code&gt;make()&lt;/code&gt; is used when you're want to prepare a channel, map, or slice. This is optimal in situations where you know the starting amount of resources you'll be inserting into these datastructurs. This removes the need for reallocated when setting up the contents of a structure.&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight plaintext"&gt;&lt;code&gt;// channel example
ch := make(chan int)
go func() { ch &amp;lt;- 1 }()
fmt.Println(&amp;lt;-ch)
// prints: 1

// map example
m := make(map[string]int)
m["one"] = 1
fmt.Println(m) // prints: map[one:1]

// slice example
s := make([]int, 10)
fmt.Println(s) // prints: [0 0 0 0 0 0 0 0 0 0]

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

&lt;/div&gt;



&lt;p&gt;In all three of the above examples, the data structure is created and ready for immediate use. In the case of the slice example, there are 10 spots already allocated and ready for data.&lt;/p&gt;

&lt;h2&gt;
  
  
  Instantiating
&lt;/h2&gt;

&lt;p&gt;Both of these built-in's shouldn't (necessarily) be the go-to methods for creating their respective types. There are specific contexts when it makes sense to use them.&lt;/p&gt;

&lt;h3&gt;
  
  
  &lt;code&gt;new()&lt;/code&gt;
&lt;/h3&gt;

&lt;p&gt;Using &lt;code&gt;new()&lt;/code&gt; is great when you need a pointer and that's all. If you already have a value (eg. an int) to be assigned then you could just create that &lt;code&gt;i := 1&lt;/code&gt; and if reference the pointer like &lt;code&gt;p := &amp;amp;i&lt;/code&gt;. A common use case for creating a pointer is when functions take a pointer and alter the underlying data.&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight plaintext"&gt;&lt;code&gt;func main() {
    year := new(int)

    if err := GetYear(year); err != nil {
        panic(err)
    }

    fmt.Println("The year is:", *year)
}

func GetYear(i *int) error {
    if *i != 0 {
        return fmt.Errorf("expected 0 value")
    }

    *i = time.Now().Year()
    return nil
}

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

&lt;/div&gt;



&lt;p&gt;When using &lt;code&gt;new()&lt;/code&gt;, &lt;code&gt;&amp;amp;&lt;/code&gt;, or another style of instantiating, you should review the specific requirements of your code given it's context and pick the clear and concise form.&lt;/p&gt;

&lt;h3&gt;
  
  
  &lt;code&gt;make()&lt;/code&gt;
&lt;/h3&gt;

&lt;p&gt;&lt;code&gt;make()&lt;/code&gt; is very powerful when you have an idea of what kind of space and records your structure will require. For example, a program may have a set of &lt;code&gt;5&lt;/code&gt; values coming in that it wants to put in a slice, and that slice will likely grow to 15 total values. The slice can be prepped like &lt;code&gt;s := make([]int, 5, 15)&lt;/code&gt;.&lt;/p&gt;

&lt;p&gt;The &lt;code&gt;5&lt;/code&gt; represents the amount of zeroed values that will be included in the slice. The &lt;code&gt;15&lt;/code&gt; is the allocated space that will be available reserved for that slice. This means that up to 10 more values can be added before the slice space needs to be reallocated and expanded.&lt;/p&gt;

&lt;p&gt;Looping over this slice would look like:&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight plaintext"&gt;&lt;code&gt;for _, i := range s {
    fmt.Print(i, ",")
}
// prints 0,0,0,0,0,

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

&lt;/div&gt;



&lt;p&gt;Note, that it only prints five &lt;code&gt;0&lt;/code&gt;'s. This is because those have been instantiated. Some more examples:&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight plaintext"&gt;&lt;code&gt;var s1 []int // length and capacity are 0
s2 := []int{} // length and capacity are 0
s3 := []int{1, 2, 3} // length and capacity are 3
s4 := make([]int, 3) // length and capacity are 3
s5 := make([]int, 3, 100) // length is 3, capacity is 100

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

&lt;/div&gt;



&lt;p&gt;In the above examples &lt;code&gt;length&lt;/code&gt; is the amount of instantiated, zero values, and capacity is the amount of spaces resevered in memory.&lt;/p&gt;

&lt;h2&gt;
  
  
  Conclusion
&lt;/h2&gt;

&lt;p&gt;Understanding how and when to use Go's built-in functions new() and make() can make a substantial difference in how you handle memory allocation and initialization in your Go programs.&lt;/p&gt;

&lt;p&gt;new() and make() serve different purposes. new(T) is used to allocate zeroed memory for a variable of type T and returns a pointer to it, useful for all types. This is particularly helpful when you need to obtain a pointer of a zero value of any data type, such as basic types or custom structs.&lt;/p&gt;

&lt;p&gt;make(), on the other hand, is designed to create complex data types like slices, maps, and channels with an underlying structure that's ready for use. It allows you to initialize these types and specify their capacity right off the bat, saving you from the costly process of memory reallocation when the data structures need to grow.&lt;/p&gt;

&lt;p&gt;But remember, although new() and make() are powerful, they are not always the best tools for the job. Regular variable declaration and initialization using var or := is often clearer and more idiomatic. In case of new(), if you already have a value to assign to the variable, you might not need new(). Instead, you can use := to declare and initialize the variable, then &amp;amp; to get its address if necessary.&lt;/p&gt;

&lt;p&gt;In the case of make(), while it's great when you have a clear idea of the capacity your data structures require, for small data structures or if you don't have a capacity in mind, using slice literals or declaring a map or channel directly can be simpler and clearer.&lt;/p&gt;

&lt;p&gt;At the end of the day, the key to writing efficient, clear, and idiomatic Go code is to understand these tools and choose the right one for your specific use case. Happy coding!&lt;/p&gt;

</description>
      <category>go</category>
    </item>
    <item>
      <title>Docker in Docker access for non-root users</title>
      <dc:creator>Jon Friesen</dc:creator>
      <pubDate>Wed, 09 Nov 2022 00:00:00 +0000</pubDate>
      <link>https://dev.to/jonfriesen/docker-in-docker-access-for-non-root-users-3ijh</link>
      <guid>https://dev.to/jonfriesen/docker-in-docker-access-for-non-root-users-3ijh</guid>
      <description>&lt;p&gt;Mounting a host machine docker daemon within a docker container is really as simple as starting the container with a volume pointing at the hosts docker socket, for example:&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight plaintext"&gt;&lt;code&gt;docker run -it --rm -v /var/run/docker.sock:/var/run/docker.sock \
    ubuntu /bin/bash

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

&lt;/div&gt;



&lt;p&gt;The socket is mounted, huzzah! From here the user could install docker with &lt;code&gt;apt install docker.io&lt;/code&gt; and be on their way. This method should work on both Linux and Mac machines. Windows machines a bit more complicated because the docker daemon needs to be remotely enabled to be accessed via a tcp connection. I'm not going to cover Windows here.&lt;/p&gt;

&lt;p&gt;To add some complexity, &lt;strong&gt;running docker as a non-root user&lt;/strong&gt; without doing a privilege escalation (like sudo) won't "just work" as the above example does. Beyond creating a dockerfile, mounting the docker socket, and creating a user there are bunch of permission "things" that need to be done to allow access.&lt;/p&gt;

&lt;p&gt;The thing that may have brought you here is this error:&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight plaintext"&gt;&lt;code&gt;Got permission denied while trying to connect to the Docker daemon socket at unix:///var/run/docker.sock: Get http://%2Fvar%2Frun%2Fdocker.sock/v1.40/containers/json: dial unix /var/run/docker.sock: connect: permission denied

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

&lt;/div&gt;



&lt;p&gt;So, why wouldn't you want to run the docker container as root? Wellllll, there are a few reasons, security, sandboxing, not giving the user root is generally a good thing. Though there are other reasons. I went down this rabbit hole because I wanted to build and run some tests within the container, these tests verified some created files were read only, but as root, no matter the permission, they were always readable which failed the test. This is different then our production configuration which worked correctly, so finding a way to get the container to mimic a production deployment was essential for having confidence in the tests.&lt;/p&gt;

&lt;p&gt;Okay, let's get into it. The docker file will look something like:&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight plaintext"&gt;&lt;code&gt;# dockerfile:
FROM ubuntu:jammy

# install the docker client and sudo
RUN apt update &amp;amp;&amp;amp; apt install -y docker.io sudo

# add 'myuser' with bash as the default terminal
# and setup the user home tree
RUN useradd myuser -s /bin/bash -m

# copy in our entrypoint script
COPY docker-entrypoint.sh /docker-entrypoint.sh

# initiate our entry point script
ENTRYPOINT ["docker-entrypoint.sh"]

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

&lt;/div&gt;



&lt;p&gt;It's important to note that we don't set the current user before running the dockerfile. This is because we need to setup the aformentioned permission "things" as root then we can move to execute the workload as the &lt;code&gt;myuser&lt;/code&gt; user.&lt;/p&gt;

&lt;p&gt;The entrypoint script:&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight plaintext"&gt;&lt;code&gt;# docker-entrypoint.sh:
#!/usr/bin/env bash

# verify the docker.sock is present in the container
# if this fails it's because the socket wasn't mounted
if [[! -S /var/run/docker.sock]]; then
    echo "docker socket is missing"
    exit 1
fi

# verify the docker.sock has read and write permissions enabled
if [[! -r /var/run/docker.sock || ! -w /var/run/docker.sock]]
then
    echo "docker socket is missing read/write permission"
    exit 1
fi

# get the group id of the docker socket
# this is inherited from the host machine
gid=$(stat -c '%g' '/var/run/docker.sock')

# lookup the group by id within the container
# if it's missing, swallow the error and create the group
# using the inherited socket group id called 'docker'
if ! getent group "$gid" &amp;gt;/dev/null; then
    addgroup --gid "$gid" docker
fi

# get the name of the group by group id.
# this doesn't necessarily have to be called 'docker'
# it could have different names on both the host machine
# and container due to system differences or group id collisions
gname=$(getent group "$gid" | cut -d: -f1)

# check if the group name is in the list of groups that
# 'myuser' has membership too. If not, add them.
if ! groups myuser | grep --quiet "\b${gname}\b"; then
    usermod --append --groups "$gid" myuser
fi

# finally switch to our user and use the legacy buildkit.
# it's important to use the legacy buildkit because of version
# mismatching running on Docker for Desktop and a minimal linux
# installation.
sudo -u myuser DOCKER_BUILDKIT=0 "$@"

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

&lt;/div&gt;



&lt;p&gt;Most of the script seems pretty straight forward until we arrive at the permission "things". This section of the script is super important because non-root users are unlikely to be in the correct group by default to have execution read/write privilege to the docker socket which brings it's permissions from the host machine.&lt;/p&gt;

&lt;p&gt;This seems pretty hacky (and it kinda is) however, the alternative which popped in my mind is why don't we &lt;strong&gt;just&lt;/strong&gt; change the permissions on the mounted docker socket? Well, because that would remove the ability for the daemon user on the host machine to continue working on it and effectively break until those permission are reset.&lt;/p&gt;

&lt;p&gt;Finally, building and running the container is pretty straight forward, building:&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight plaintext"&gt;&lt;code&gt;docker build -t docker-in-docker .

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

&lt;/div&gt;



&lt;p&gt;and running has two possible parameters:&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight plaintext"&gt;&lt;code&gt;# linux
docker run -it --rm -v /var/run/docker.sock:/var/run/docker.sock \
    docker-in-docker some-command

# macos (note the '.raw' on the end of the docker.sock)
# this .raw isnt necessary if running as the root user
# but is if you're not
docker run -it --rm -v /var/run/docker.sock.raw:/var/run/docker.sock \
    docker-in-docker some-command

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

&lt;/div&gt;



&lt;p&gt;As a small disclaimer, the techniques I covered here are great for testing, CI/CD tooling, one-off's, but definitely should not be run as a standard production environment. Mounting docker in docker brings in all sorts of risk and issues.&lt;/p&gt;

&lt;p&gt;Finally, I'd like to give a quick shout out to my &lt;a href="https://twitter.com/kamaln7"&gt;colleague and friend Kamal&lt;/a&gt; who got me through the permission chunk of this!&lt;/p&gt;

</description>
      <category>docker</category>
    </item>
    <item>
      <title>App Platform: Automatically deploy pre-built container images on push</title>
      <dc:creator>Jon Friesen</dc:creator>
      <pubDate>Mon, 10 Oct 2022 00:00:00 +0000</pubDate>
      <link>https://dev.to/jonfriesen/app-platform-automatically-deploy-pre-built-container-images-on-push-43lp</link>
      <guid>https://dev.to/jonfriesen/app-platform-automatically-deploy-pre-built-container-images-on-push-43lp</guid>
      <description>&lt;p&gt;App Platform has supported running container images from DigitalOcean Container Registry (DOCR) from the very start, however, a much requested feature is the ability to autodeploy a container when the a new image was pushed to a specific tag. With the most recent release this feature has been added and is available for all!&lt;/p&gt;

&lt;blockquote&gt;
&lt;p&gt;Note: this feature is not supported for DockerHub.&lt;/p&gt;
&lt;/blockquote&gt;

&lt;h2&gt;
  
  
  How autodeploy works
&lt;/h2&gt;

&lt;p&gt;When autodeploy is enabled for a DOCR Image component in App Platform the container registry is monitored and upon a new image push App Platform checks the image digest for a target tag and &lt;strong&gt;if&lt;/strong&gt; it is different than the most recently deployed version that new image is deployed.&lt;/p&gt;

&lt;p&gt;So this means that when pushing a tag you'll probably want to use a descriptive tag that represent the latest version of that image. For example, &lt;code&gt;production&lt;/code&gt;, &lt;code&gt;staging&lt;/code&gt;, &lt;code&gt;dev&lt;/code&gt; are common.&lt;/p&gt;

&lt;h2&gt;
  
  
  Enabling autodeploy
&lt;/h2&gt;

&lt;h3&gt;
  
  
  UI: During creation
&lt;/h3&gt;

&lt;p&gt;When creating an App or Component, select your DOCR repository and image, then check the &lt;code&gt;Autodeploy&lt;/code&gt; checkbox.&lt;/p&gt;

&lt;p&gt;&lt;a href="https://res.cloudinary.com/practicaldev/image/fetch/s--dVCToEv5--/c_limit%2Cf_auto%2Cfl_progressive%2Cq_auto%2Cw_880/https://jonfriesen.ca/_next/static/media/app-create.8c9432fe.png" class="article-body-image-wrapper"&gt;&lt;img src="https://res.cloudinary.com/practicaldev/image/fetch/s--dVCToEv5--/c_limit%2Cf_auto%2Cfl_progressive%2Cq_auto%2Cw_880/https://jonfriesen.ca/_next/static/media/app-create.8c9432fe.png" alt="A screenshot of the App Platform creation menu with autodeploy enabled." width="880" height="798"&gt;&lt;/a&gt;&lt;/p&gt;

&lt;h3&gt;
  
  
  UI: Exising image components
&lt;/h3&gt;

&lt;p&gt;If you already have a DOCR Image deployed autodeploy can be enabled in the settings of that component.&lt;/p&gt;

&lt;p&gt;&lt;a href="https://res.cloudinary.com/practicaldev/image/fetch/s--8Qp-88cT--/c_limit%2Cf_auto%2Cfl_progressive%2Cq_auto%2Cw_880/https://jonfriesen.ca/_next/static/media/app-update.81efd686.png" class="article-body-image-wrapper"&gt;&lt;img src="https://res.cloudinary.com/practicaldev/image/fetch/s--8Qp-88cT--/c_limit%2Cf_auto%2Cfl_progressive%2Cq_auto%2Cw_880/https://jonfriesen.ca/_next/static/media/app-update.81efd686.png" alt="A screenshot of the App Platform component settings menu with autodeploy enabled." width="880" height="830"&gt;&lt;/a&gt;&lt;/p&gt;

&lt;h3&gt;
  
  
  App Spec: Enabling within the spec
&lt;/h3&gt;

&lt;p&gt;For power users, enabling autodeploy is as easy as adding a small yaml structure to your existing image spec:&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight plaintext"&gt;&lt;code&gt;deploy_on_push:
  enabled: true

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

&lt;/div&gt;



&lt;p&gt;for example:&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight plaintext"&gt;&lt;code&gt;name: docr-autodeploy-example
region: ams
services:
- http_port: 8080
  image:
    deploy_on_push:
      enabled: true
    registry_type: DOCR
    repository: go-info-webserver
    tag: latest
  instance_count: 1
  instance_size_slug: basic-xxs
  name: go-info-webserver
  routes:
  - path: /

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

&lt;/div&gt;



&lt;h2&gt;
  
  
  An GitHub Actions example
&lt;/h2&gt;

&lt;p&gt;As a fan of GitHub Actions, here's a simple workflow that does the following:&lt;/p&gt;

&lt;ol&gt;
&lt;li&gt;Builds the docker image with two tags:

&lt;ol&gt;
&lt;li&gt;the git commit short hash&lt;/li&gt;
&lt;li&gt;&lt;code&gt;latest&lt;/code&gt;&lt;/li&gt;
&lt;/ol&gt;


&lt;/li&gt;
&lt;li&gt;Installs the &lt;a href="https://github.com/digitalocean/doctl"&gt;doctl&lt;/a&gt; commandline tool&lt;/li&gt;
&lt;li&gt;Authenticates with the registry attached to a DigitalOcean account&lt;/li&gt;
&lt;li&gt;Pushes the image with all tags&lt;/li&gt;
&lt;/ol&gt;

&lt;p&gt;Paired with the app spec above which targest the &lt;code&gt;latest&lt;/code&gt; image tag, when the underlying image changes (via digest checking) the new image will be deployed. If the digest has not changed no deployment will occur.&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight plaintext"&gt;&lt;code&gt;name: Push Docker Image to DOCR

on:
  push:
    branches: ["master"]
env:
  REGISTRY: "registry.digitalocean.com/jon"
  IMAGE_NAME: "go-info-webserver"
jobs:
  build:
    runs-on: ubuntu-latest
    steps:
    - uses: actions/checkout@v3
    - name: Build the Docker image
      run: docker build --file docker/Dockerfile --tag $(echo $REGISTRY)/$(echo $IMAGE_NAME):$(echo $GITHUB_SHA | head -c7) --tag $(echo $REGISTRY)/$(echo $IMAGE_NAME):latest .

    - name: Install doctl
      uses: digitalocean/action-doctl@v2
      with:
        token: ${{ secrets.DIGITALOCEAN_ACCESS_TOKEN }}

    - name: Auth with DOCR
      run: doctl registry login --expiry-seconds 1000

    - name: Push image to DOCR
      run: docker push $(echo $REGISTRY)/$(echo $IMAGE_NAME) --all-tags

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

&lt;/div&gt;



&lt;blockquote&gt;
&lt;p&gt;When an image is pushed to a registry with a tag that has already been used, the new image will take that tag, untagging the old image.&lt;/p&gt;
&lt;/blockquote&gt;

</description>
      <category>appplatform</category>
      <category>digitalocean</category>
      <category>github</category>
      <category>githubactions</category>
    </item>
    <item>
      <title>Adding middleware to Go HTTP client requests</title>
      <dc:creator>Jon Friesen</dc:creator>
      <pubDate>Wed, 05 Oct 2022 00:00:00 +0000</pubDate>
      <link>https://dev.to/jonfriesen/adding-middleware-to-go-http-client-3j97</link>
      <guid>https://dev.to/jonfriesen/adding-middleware-to-go-http-client-3j97</guid>
      <description>&lt;p&gt;The Go standard library has fantastic support for making HTTP requests. However, sometimes, a request needs to be modified or an action needs to be taken upon response (eg. logging a response).&lt;/p&gt;

&lt;p&gt;In many cases, adding these logs to the every request would involve a lot of duplicate code. In other cases accessing the client might not be possible because of restricted access in a different package or third party library. Thus, I introduce &lt;a href="https://pkg.go.dev/net/http#RoundTripper"&gt;RoundTrippers&lt;/a&gt;.&lt;/p&gt;

&lt;p&gt;A RoundTripper can be added to an http client and executes a http transaction allowing the request to be inspected and modified and the response to be inspected and modified.&lt;/p&gt;

&lt;p&gt;A RoundTripper can be set on a http client Transport. The interface looks like:&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight plaintext"&gt;&lt;code&gt;type RoundTripper interface {
    RoundTrip(*http.Request) (*http.Response, error)
}

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

&lt;/div&gt;



&lt;p&gt;and a RoundTripper is set on a client like:&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight plaintext"&gt;&lt;code&gt;client := &amp;amp;http.Client{
    Transport: myRoundTripper,
}

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

&lt;/div&gt;



&lt;p&gt;The http.Client will resolve to the &lt;code&gt;DefaultTransport&lt;/code&gt; if the client transport is &lt;code&gt;nil&lt;/code&gt;. It's fairly easy to chain RoundTrippers as middleware, the DefaultTransport round tripper should be considered as a base since it comes with handy defaults:&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight plaintext"&gt;&lt;code&gt;var DefaultTransport RoundTripper = &amp;amp;Transport{
    Proxy: ProxyFromEnvironment,
    DialContext: defaultTransportDialContext(&amp;amp;net.Dialer{
        Timeout: 30 * time.Second,
        KeepAlive: 30 * time.Second,
    }),
    ForceAttemptHTTP2: true,
    MaxIdleConns: 100,
    IdleConnTimeout: 90 * time.Second,
    TLSHandshakeTimeout: 10 * time.Second,
    ExpectContinueTimeout: 1 * time.Second,
}

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

&lt;/div&gt;



&lt;p&gt;Now that the basics have been covered we can use a single chaining example which I originally saw by &lt;a href="https://gowebexamples.com/advanced-middleware/"&gt;Philipp from GoWebExamples.com&lt;/a&gt; applied to web server middleware. It's a simple little pattern that's easy to understand.&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight plaintext"&gt;&lt;code&gt;// internalRoundTripper is a holder function to make the process of
// creating middleware a bit easier without requiring the consumer to
// implement the RoundTripper interface.
type internalRoundTripper func(*http.Request) (*http.Response, error)

func (rt internalRoundTripper) RoundTrip(req *http.Request)
                                            (*http.Response, error) {
    return rt(req)
}

// Middleware is our middleware creation functionality.
type Middleware func(http.RoundTripper) http.RoundTripper

// Chain is a handy function to wrap a base RoundTripper (optional)
// with the middlewares.
func Chain(rt http.RoundTripper, middlewares ...Middleware)
                                                    http.RoundTripper {
    if rt == nil {
        rt = http.DefaultTransport
    }

    for _, m := range middlewares {
        rt = m(rt)
    }

    return rt
}

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

&lt;/div&gt;



&lt;p&gt;From here writing custom middlewares for your needs is straightforward. Two examples below:&lt;/p&gt;

&lt;ul&gt;
&lt;li&gt;CustomTimer executes a function after the RoundTrip has finished and shows the time since. This demonstrates how operates can occur before the request is made, in this case we are capturing the start time and then executing code after the request has been made using a &lt;code&gt;defer&lt;/code&gt;.&lt;/li&gt;
&lt;li&gt;DumpResponse prints the response body to &lt;code&gt;stdout&lt;/code&gt;. Similarly to CustomTimer, a defer is used to run the dump after the request has been made. The difference here is named response are used to access the response data.
&lt;/li&gt;
&lt;/ul&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight plaintext"&gt;&lt;code&gt;// CustomTimer takes a writer and will output a request duration.
func CustomTimer(w io.Writer) Middleware {
    return func(rt http.RoundTripper) http.RoundTripper {
        return internalRoundTripper(func(req *http.Request)
                                            (*http.Response, error) {
            startTime := time.Now()
            defer func() {
                fmt.Fprintf(w, "&amp;gt;&amp;gt;&amp;gt; request duration: %s",
                    time.Since(startTime))
            }()

            return rt.RoundTrip(req)
        })
    }
}

// DumpResponse uses dumps the response body to console.
func DumpResponse(includeBody bool) Middleware {
    return func(rt http.RoundTripper) http.RoundTripper {
        return internalRoundTripper(func(req *http.Request)
                                    (resp *http.Response, err error) {
            defer func() {
                if err == nil {
                    o, err := httputil.DumpResponse(resp, includeBody)
                    if err != nil {
                        panic(err)
                    }

                    fmt.Println(string(o))
                }
            }()

            return rt.RoundTrip(req)
        })
    }
}

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

&lt;/div&gt;



&lt;p&gt;Once you've written middleware that fits your needs, adding them to your HTTP client is as easy as creating an &lt;code&gt;http.Client&lt;/code&gt; and setting the &lt;code&gt;Transport&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;client := http.Client{
    // Using the Chain function, we can add middlewares to our base
    // RoundTripper. These middlewares will run on every http request. 
    Transport: Chain(nil, CustomTimer(os.Stdout), DumpResponse(false)),
}

// Start making requests
_, err := client.Get("http://jonfriesen.ca")
if err != nil {
    panic(err)
}

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

&lt;/div&gt;



&lt;p&gt;Another great use for RoundTripper middleware is within third party clients. For example, the GitHub Go library does not have native support for adding headers to requests it makes. It's common for third party clients to support setting the &lt;code&gt;http.Client&lt;/code&gt;, for example:&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight plaintext"&gt;&lt;code&gt;// AddHeader adds a header to the request.
func AddHeader(key, value string) Middleware {
    return func(rt http.RoundTripper) http.RoundTripper {
        return internalRoundTripper(func(req *http.Request)
                                            (*http.Response, error) {
            header := req.Header
            if header == nil {
                header = make(http.Header)
            }

            header.Set(key, value)

            return rt.RoundTrip(req)
        })
    }
}

func main() {
    userClient := github.NewClient(&amp;amp;http.Client{
        Transport: Chain(nil, AddHeader("key", "value")),
    })
}

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

&lt;/div&gt;



</description>
      <category>go</category>
    </item>
    <item>
      <title>App Platform: Hosting static NextJS projects</title>
      <dc:creator>Jon Friesen</dc:creator>
      <pubDate>Mon, 19 Sep 2022 00:00:00 +0000</pubDate>
      <link>https://dev.to/jonfriesen/app-platform-hosting-static-nextjs-projects-30d5</link>
      <guid>https://dev.to/jonfriesen/app-platform-hosting-static-nextjs-projects-30d5</guid>
      <description>&lt;p&gt;App Platform has great support for static sites, building and pushing projects to over 100 points of presence around the world ensuring the fastest load times for users. NextJS is provides a great developer experience, however opinionated and can require some unique platform services to be hosted while remaining free or very low cost.&lt;/p&gt;

&lt;p&gt;App Platform does not employ this functionality (as of today) but that's not an issue because this can be worked around!&lt;/p&gt;

&lt;h2&gt;
  
  
  NextJS configurations
&lt;/h2&gt;

&lt;p&gt;In your &lt;code&gt;next.config.js&lt;/code&gt; folder you're going need a couple additions:&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight plaintext"&gt;&lt;code&gt;// next.config.js
module.exports = {
    /**
     * NextJS requires serverside components to do image optimization.
     * Unfortunately, hosting via SSG/Static means you will miss out on
     * this utility which will provide appropriately sized images for
     * the devices users are accessing your app from.
     * 
     * As a side note, you can write a custom image loader which
     * reimplements this functionality but that is beyond the scope of
     * this article.
     */
    images: {
        unoptimized: true,
    },

    /**
     * Trailing slashes places the generated pages of a nextjs app
     * within a folder.
     * 
     * Eg. instead of having an `about.html` a `about/index.html` will
     * be generated.
     * 
     * This provides pretty urls, so instead of
     * `your-app.com/about.html` you'll have `your-site.com/about`.
     * 
     * This is optional.
     */
    trailingSlash: true,
}

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

&lt;/div&gt;



&lt;p&gt;In addition you will need to update the build command that is used to generate your app. This can be done in a few different places, I prefer to add it to my &lt;code&gt;package.json&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;{
    // ...
    "scripts": {
        // .../
        "build": "next build &amp;amp;&amp;amp; next export -o build",
        // ...
    },
    // ...
}

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

&lt;/div&gt;



&lt;blockquote&gt;
&lt;p&gt;Note the &lt;code&gt;-o build&lt;/code&gt; argument, this will put your static site in a &lt;code&gt;build&lt;/code&gt; directory. It's a good idea to add this to your &lt;code&gt;.gitignore&lt;/code&gt;.&lt;/p&gt;
&lt;/blockquote&gt;

&lt;h2&gt;
  
  
  App Platform configurations
&lt;/h2&gt;

&lt;p&gt;Create your app using the wizard in the DigitalOcean Apps cloud dashboard. Ensure that you use the appropriate build command, eg from above:&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight plaintext"&gt;&lt;code&gt;npm run build

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

&lt;/div&gt;



&lt;p&gt;You will need to set your &lt;code&gt;catchall&lt;/code&gt; in &lt;code&gt;Settings &amp;gt; &amp;lt;your_component&amp;gt; &amp;gt; Custom Pages&lt;/code&gt;. Set this value to &lt;code&gt;index.html&lt;/code&gt;.&lt;/p&gt;

&lt;p&gt;Some NextJS apps will require a &lt;code&gt;NEXT_PUBLIC_SITE_URL&lt;/code&gt; environment variable. With App Platform bind variables can be used to create an environment variable for your static site component like:&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight plaintext"&gt;&lt;code&gt;NEXT_PUBLIC_SITE_URL=${APP_URL}

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

&lt;/div&gt;



&lt;blockquote&gt;
&lt;p&gt;Note: &lt;code&gt;${APP_URL}&lt;/code&gt; will be auto-filled with the apps primary URL whether that is a custom URL or the provided &lt;code&gt;some-value.ondigitalocean.app&lt;/code&gt; domain.&lt;/p&gt;
&lt;/blockquote&gt;

&lt;p&gt;Finally, ensure that your output directory in the same component settings from above is set to the build directory. If you used my example above of &lt;code&gt;-o build&lt;/code&gt; then this directory will be &lt;code&gt;build&lt;/code&gt;.&lt;/p&gt;

&lt;p&gt;App Platform apps are described via an &lt;code&gt;app spec&lt;/code&gt;, here's an example app spec that is configured for a NextJS SSG project (it's this site 😉).&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight plaintext"&gt;&lt;code&gt;domains:
- domain: jonfriesen.ca
  type: PRIMARY
  zone: jonfriesen.ca
name: portfolio
region: tor
static_sites:
- build_command: npm run build
  catchall_document: index.html
  environment_slug: node-js
  envs:
  - key: NEXT_PUBLIC_SITE_URL
    scope: BUILD_TIME
    value: ${APP_URL}
  github:
    branch: main
    deploy_on_push: true
    repo: jonfriesen/jonfriesen.ca
  name: portfolio
  output_dir: build
  routes:
  - path: /
  source_dir: /

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

&lt;/div&gt;



</description>
    </item>
    <item>
      <title>Handling container shutdowns in app code</title>
      <dc:creator>Jon Friesen</dc:creator>
      <pubDate>Mon, 15 Aug 2022 00:00:00 +0000</pubDate>
      <link>https://dev.to/jonfriesen/handling-container-shutdowns-in-app-code-3e1n</link>
      <guid>https://dev.to/jonfriesen/handling-container-shutdowns-in-app-code-3e1n</guid>
      <description>&lt;p&gt;Most small apps start out running on a PaaS these days such as &lt;a href="https://www.digitalocean.com/products/app-platform"&gt;DigitalOcean App Platform&lt;/a&gt;. Platforms like these control the environment pre and post app execution. This isn't a problem when it comes to pre-execution as you can run your startup tasks when your app is started.&lt;/p&gt;

&lt;p&gt;However, running clean up code when the app, or more specifically the container is being shutdown isn't as straightforward. This is where we can feed two birds with one slice of bread using &lt;a href="https://www.gnu.org/software/libc/manual/html_node/Termination-Signals.html"&gt;Linux Signals&lt;/a&gt;.&lt;/p&gt;

&lt;p&gt;The signal I use personally is &lt;code&gt;SIGTERM&lt;/code&gt; -- which indicates intent to terminate the process. This signal is sent by the operating service when the client container is going to be shutdown. While you &lt;em&gt;can&lt;/em&gt; catch this signal and prevent shutdown, most of services will send a &lt;code&gt;SIGKILL&lt;/code&gt; signal forcing shutdown of the app after a certain time duration. In some cases this is configurable.&lt;/p&gt;

&lt;p&gt;We feed two birds because using &lt;code&gt;SIGTERM&lt;/code&gt; an app can:&lt;/p&gt;

&lt;ol&gt;
&lt;li&gt;execute clean up code&lt;/li&gt;
&lt;li&gt;gracefully shutdown the application&lt;/li&gt;
&lt;/ol&gt;

&lt;p&gt;This ensures that any operations an app is in the middle of, have &lt;em&gt;some&lt;/em&gt; time to exit. So what does that look like?&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight plaintext"&gt;&lt;code&gt;// javascript
process.on('SIGTERM', () =&amp;gt; {
    console.info('SIGTERM signal received.');

    /**
     * This is where cleanup code can be run. For example, closing down the http server.
     */
    console.log('Closing http server.');
    server.close(() =&amp;gt; {
        console.log('Http server closed.');
    });

    process.exit(0)
});

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

&lt;/div&gt;



&lt;p&gt;This example snippet runs in a nodejs environment, attaching an anonymous function &lt;code&gt;() =&amp;gt; {...}&lt;/code&gt; to the process when &lt;code&gt;SIGTERM&lt;/code&gt; signal occurs. The clean up code will run and the &lt;code&gt;server&lt;/code&gt; which is an http server in this example, but could be any service time, is closed, and &lt;code&gt;process.exit(0)&lt;/code&gt; is fired.&lt;/p&gt;

&lt;blockquote&gt;
&lt;p&gt;Note: Exit code &lt;code&gt;0&lt;/code&gt; means the process exited successfully, any other exit code indicates an error of some type.&lt;/p&gt;
&lt;/blockquote&gt;

&lt;h2&gt;
  
  
  Further reading
&lt;/h2&gt;

&lt;p&gt;&lt;a href="https://cloud.google.com/blog/products/containers-kubernetes/kubernetes-best-practices-terminating-with-grace"&gt;Kubernetes best practices: terminating with grace&lt;/a&gt; is a great article which overlaps heavily with the content above with additional detail on expanding the durations and how these signals work in Kubernetes.&lt;/p&gt;

</description>
    </item>
    <item>
      <title>App Platform: Handling GitLab submodules</title>
      <dc:creator>Jon Friesen</dc:creator>
      <pubDate>Mon, 05 Apr 2021 00:00:00 +0000</pubDate>
      <link>https://dev.to/jonfriesen/app-platform-handling-gitlab-submodules-5apm</link>
      <guid>https://dev.to/jonfriesen/app-platform-handling-gitlab-submodules-5apm</guid>
      <description>&lt;p&gt;Git submodules are a bit of a pain; that said we are iterating on this and trying to make it better in the future. I do have a workaround that will hopefully handle your needs:&lt;/p&gt;

&lt;blockquote&gt;
&lt;p&gt;This assumes that your submodule is hosted in the same account/team as your app repository.&lt;/p&gt;
&lt;/blockquote&gt;

&lt;p&gt;When an app is created from a GitLab project, we create and assign a deploy key to that project. Our build system uses that deploy key to check out the repository code as well as all submodule repositories. This means we need to enable that deploy key on the submodules repository.&lt;/p&gt;

&lt;p&gt;Get the deploy key UUID from the app repository by going to the project, then&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight plaintext"&gt;&lt;code&gt;1. Settings
2. Repository
3. Deploy Keys
4. Copy the deploy key name (it’s a UUID)
5. then go to the submodule repository, and

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

&lt;/div&gt;



&lt;p&gt;&lt;a href="https://res.cloudinary.com/practicaldev/image/fetch/s--cfRPcEMu--/c_limit%2Cf_auto%2Cfl_progressive%2Cq_auto%2Cw_880/https://jonfriesen.ca/_next/static/media/deploy-key.61764db5.png" class="article-body-image-wrapper"&gt;&lt;img src="https://res.cloudinary.com/practicaldev/image/fetch/s--cfRPcEMu--/c_limit%2Cf_auto%2Cfl_progressive%2Cq_auto%2Cw_880/https://jonfriesen.ca/_next/static/media/deploy-key.61764db5.png" alt="" width="880" height="550"&gt;&lt;/a&gt;&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight plaintext"&gt;&lt;code&gt;1. Settings
2. Repository
3. Deploy Keys
4. Privately accessible deploy keys
5. Search for the deploy key matching the UUID copied from the above
   step and click Enable.

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

&lt;/div&gt;



&lt;p&gt;&lt;a href="https://res.cloudinary.com/practicaldev/image/fetch/s--wdn5VZ85--/c_limit%2Cf_auto%2Cfl_progressive%2Cq_auto%2Cw_880/https://jonfriesen.ca/_next/static/media/deploy-key-enable.070192a5.png" class="article-body-image-wrapper"&gt;&lt;img src="https://res.cloudinary.com/practicaldev/image/fetch/s--wdn5VZ85--/c_limit%2Cf_auto%2Cfl_progressive%2Cq_auto%2Cw_880/https://jonfriesen.ca/_next/static/media/deploy-key-enable.070192a5.png" alt="" width="880" height="568"&gt;&lt;/a&gt;&lt;/p&gt;

&lt;p&gt;You will also need to use the git ssh URL instead of the git https url in your .gitmodules file. So &lt;a href="//mailto:git@gitlab.com"&gt;git@gitlab.com&lt;/a&gt;:owner/repo.git instead of &lt;a href="https://gitlab.com/owner/repo.git"&gt;https://gitlab.com/owner/repo.git&lt;/a&gt;.&lt;/p&gt;

</description>
    </item>
    <item>
      <title>App Platform: How to set an app timezone?</title>
      <dc:creator>Jon Friesen</dc:creator>
      <pubDate>Tue, 16 Mar 2021 00:00:00 +0000</pubDate>
      <link>https://dev.to/jonfriesen/app-platform-how-to-set-an-app-timezone-e1c</link>
      <guid>https://dev.to/jonfriesen/app-platform-how-to-set-an-app-timezone-e1c</guid>
      <description>&lt;p&gt;Apps that run on and built by App Platform use a fairly standard Linux container environment. This means that lots of standard linux configurations work on apps.&lt;/p&gt;

&lt;p&gt;To set the timezone of an app, set the &lt;code&gt;TZ&lt;/code&gt; environment variable, this can be as simple as:&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight plaintext"&gt;&lt;code&gt;TZ='Africa/Lagos'

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

&lt;/div&gt;



&lt;p&gt;Or using more &lt;a href="https://www.ibm.com/support/pages/about-tz-environment-variable"&gt;complex timezone configurations&lt;/a&gt;.&lt;/p&gt;

</description>
    </item>
    <item>
      <title>App Platform: Injecting files from Environment Variables</title>
      <dc:creator>Jon Friesen</dc:creator>
      <pubDate>Wed, 03 Mar 2021 00:00:00 +0000</pubDate>
      <link>https://dev.to/jonfriesen/app-platform-injecting-files-from-environment-variables-9g1</link>
      <guid>https://dev.to/jonfriesen/app-platform-injecting-files-from-environment-variables-9g1</guid>
      <description>&lt;p&gt;App Platform apps (that don't use dockerfiles) are built using &lt;a href="https://buildpacks.io/"&gt;Cloud Native Build Packs&lt;/a&gt;, which turn your code into a OCI image that is run on a secured, shared Kubernetes instance. App Platform offers the ability to apply environment variables to your app, in many cases app secrets are stored in these env vars, and in less common cases the apps require these secrets to exist as a file on the filesystem.&lt;/p&gt;

&lt;h3&gt;
  
  
  Some options to make this happen are:
&lt;/h3&gt;

&lt;ul&gt;
&lt;li&gt;Commit the secret to the app git repository so it's present when the build occurs.

&lt;ul&gt;
&lt;li&gt;The obvious drawback here is that the secret is in the git and the git history. This is unacceptable in most cases.&lt;/li&gt;
&lt;/ul&gt;


&lt;/li&gt;
&lt;li&gt;Convert the App to use a dockerfile and echo the environment variable to disk with the dockerfile.

&lt;ul&gt;
&lt;li&gt;Slightly better than the first option, this method still persists your secret to the OCI image.&lt;/li&gt;
&lt;/ul&gt;


&lt;/li&gt;
&lt;li&gt;Finally, explicitly take over the run command and inject the file at run time.

&lt;ul&gt;
&lt;li&gt;This method does not persist the secret anywhere in an unencrypted fashion.&lt;/li&gt;
&lt;li&gt;It ensure that the right version of your secret is present.&lt;/li&gt;
&lt;li&gt;The drawback is it your app &lt;code&gt;run_command&lt;/code&gt; needs to be manually set.&lt;/li&gt;
&lt;/ul&gt;


&lt;/li&gt;
&lt;/ul&gt;

&lt;h2&gt;
  
  
  How do we do this?
&lt;/h2&gt;

&lt;p&gt;&lt;strong&gt;1.&lt;/strong&gt; Add the environment variable to your app and check the &lt;code&gt;Encrypt&lt;/code&gt; checkbox.&lt;/p&gt;

&lt;p&gt;&lt;strong&gt;2.&lt;/strong&gt; Select the component that requires the secret and &lt;code&gt;Edit&lt;/code&gt; the &lt;em&gt;Commands&lt;/em&gt; to look something like&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight plaintext"&gt;&lt;code&gt;echo "${APP_CERT}" &amp;gt; jwt.cer &amp;amp;&amp;amp; &amp;lt;your_apps_run_command&amp;gt;

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

&lt;/div&gt;



&lt;p&gt;In this snippet, the &lt;code&gt;APP_CERT&lt;/code&gt; environment variable writen to a file called &lt;code&gt;jwt.cer&lt;/code&gt; and then the apps execution code is ran.&lt;/p&gt;

&lt;h2&gt;
  
  
  Further Considerations
&lt;/h2&gt;

&lt;p&gt;In some cases you may need to encode your file before saving it as an environment variable, which will require decoding it.&lt;/p&gt;

&lt;h3&gt;
  
  
  Encoding your file using base64
&lt;/h3&gt;

&lt;p&gt;The &lt;code&gt;base64&lt;/code&gt; tool comes with Linux and MacOS by default, getting a base64 representation of your file can be down with:&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight plaintext"&gt;&lt;code&gt;cat &amp;lt;your_file&amp;gt; | base64

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

&lt;/div&gt;



&lt;p&gt;this also means your file will need to be decoded before being written to disk. Update your run command to:&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight plaintext"&gt;&lt;code&gt;echo "${APP_CERT}" | base64 --decode &amp;gt; jwt.cer &amp;amp;&amp;amp; &amp;lt;your_apps_run_command&amp;gt;

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

&lt;/div&gt;



</description>
    </item>
    <item>
      <title>App Platform: How to set specific NodeJS version?</title>
      <dc:creator>Jon Friesen</dc:creator>
      <pubDate>Wed, 21 Oct 2020 00:00:00 +0000</pubDate>
      <link>https://dev.to/jonfriesen/app-platform-how-to-set-specific-nodejs-version-2alk</link>
      <guid>https://dev.to/jonfriesen/app-platform-how-to-set-specific-nodejs-version-2alk</guid>
      <description>&lt;p&gt;NodeJS projects have an optional configuration in their &lt;code&gt;package.json&lt;/code&gt; for indicating the supported engine(s) for an app. This can look like:&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight plaintext"&gt;&lt;code&gt;{ 
  "engines" : { 
    "node" : "12.19.0" 
  }
}

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

&lt;/div&gt;



&lt;p&gt;ranges are also supported, for example:&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight plaintext"&gt;&lt;code&gt;{ 
  "engines" : { 
    "node" : "&amp;gt;=12.0.0 &amp;lt;=14.0.0" 
  }
}

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

&lt;/div&gt;



&lt;p&gt;this range says an app can be run on NodeJS 12 to 14 (inclusively).&lt;/p&gt;

&lt;p&gt;&lt;a href="https://docs.npmjs.com/cli/v8/configuring-npm/package-json#engines"&gt;Click here for more info on NoedJS &lt;code&gt;engines&lt;/code&gt;&lt;/a&gt;.&lt;/p&gt;

</description>
      <category>digitalocean</category>
      <category>appplatform</category>
    </item>
  </channel>
</rss>
