211 lines
7.1 KiB
HTML
211 lines
7.1 KiB
HTML
<!DOCTYPE html>
|
|
<html>
|
|
<head>
|
|
<meta charset="utf-8" />
|
|
<meta name="viewport" content="width=device-width, initial-scale=1" />
|
|
<link
|
|
rel="stylesheet"
|
|
href="https://cdnjs.cloudflare.com/ajax/libs/github-markdown-css/5.2.0/github-markdown-dark.min.css"
|
|
/>
|
|
<link rel="preconnect" href="https://fonts.googleapis.com" />
|
|
<link rel="preconnect" href="https://fonts.gstatic.com" crossorigin />
|
|
<link
|
|
href="https://fonts.googleapis.com/css2?family=Inter&family=JetBrains+Mono&display=swap"
|
|
rel="stylesheet"
|
|
/>
|
|
<title>haunt98 posts</title>
|
|
</head>
|
|
<style>
|
|
.markdown-body {
|
|
box-sizing: border-box;
|
|
min-width: 200px;
|
|
max-width: 980px;
|
|
margin: 0 auto;
|
|
padding: 45px;
|
|
}
|
|
|
|
@media (max-width: 767px) {
|
|
.markdown-body {
|
|
padding: 15px;
|
|
}
|
|
}
|
|
|
|
.markdown-body {
|
|
font-family: "Inter", sans-serif;
|
|
}
|
|
|
|
.markdown-body code,
|
|
.markdown-body pre {
|
|
font-family: "JetBrains Mono", monospace;
|
|
}
|
|
</style>
|
|
<body class="markdown-body">
|
|
<div><a href="index.html">Index</a></div>
|
|
<h1>
|
|
<a
|
|
id="user-content-dockerfile-for-go"
|
|
class="anchor"
|
|
aria-hidden="true"
|
|
href="#dockerfile-for-go"
|
|
><span aria-hidden="true" class="octicon octicon-link"></span></a
|
|
>Dockerfile for Go
|
|
</h1>
|
|
<p>
|
|
Each time I start a new Go project, I repeat many steps. Like set up
|
|
<code>.gitignore</code>, CI configs, Dockerfile, ...
|
|
</p>
|
|
<p>So I decide to have a baseline Dockerfile like this:</p>
|
|
<div class="highlight highlight-source-dockerfile">
|
|
<pre><span class="pl-k">FROM</span> golang:1.20-bullseye as builder
|
|
|
|
<span class="pl-k">RUN</span> go install golang.org/dl/go1.20@latest \
|
|
&& go1.20 download
|
|
|
|
<span class="pl-k">WORKDIR</span> /build
|
|
|
|
<span class="pl-k">COPY</span> go.mod .
|
|
<span class="pl-k">COPY</span> go.sum .
|
|
<span class="pl-k">COPY</span> vendor .
|
|
<span class="pl-k">COPY</span> . .
|
|
|
|
<span class="pl-k">RUN</span> CGO_ENABLED=0 GOOS=linux GOARCH=amd64 GOAMD64=v3 go build -o ./app -tags timetzdata -trimpath -ldflags=<span class="pl-s">"-s -w"</span> .
|
|
|
|
<span class="pl-k">FROM</span> gcr.io/distroless/base-debian11
|
|
|
|
<span class="pl-k">COPY</span> --from=builder /build/app /app
|
|
|
|
<span class="pl-k">ENTRYPOINT</span> [<span class="pl-s">"/app"</span>]</pre>
|
|
</div>
|
|
<p>
|
|
I use
|
|
<a
|
|
href="https://docs.docker.com/develop/develop-images/multistage-build/"
|
|
rel="nofollow"
|
|
>multi-stage build</a
|
|
>
|
|
to keep my image size small. First stage is
|
|
<a href="https://hub.docker.com/_/golang" rel="nofollow"
|
|
>Go official image</a
|
|
>, second stage is
|
|
<a href="https://github.com/GoogleContainerTools/distroless">Distroless</a
|
|
>.
|
|
</p>
|
|
<p>
|
|
Before Distroless, I use
|
|
<a href="https://hub.docker.com/_/alpine" rel="nofollow"
|
|
>Alpine official image</a
|
|
>, There is a whole discussion on the Internet to choose which is the best
|
|
base image for Go. After reading some blogs, I discover Distroless as a
|
|
small and secure base image. So I stick with it for a while.
|
|
</p>
|
|
<p>
|
|
Also, remember to match Distroless Debian version with Go official image
|
|
Debian version.
|
|
</p>
|
|
<div class="highlight highlight-source-dockerfile">
|
|
<pre><span class="pl-k">FROM</span> golang:1.20-bullseye as builder</pre>
|
|
</div>
|
|
<p>
|
|
This is Go image I use as a build stage. This can be official Go image or
|
|
custom image is required in some companies.
|
|
</p>
|
|
<div class="highlight highlight-source-dockerfile">
|
|
<pre><span class="pl-k">RUN</span> go install golang.org/dl/go1.20@latest \
|
|
&& go1.20 download</pre>
|
|
</div>
|
|
<p>
|
|
This is optional. In my case, my company is slow to update Go image so I
|
|
use this trick to install latest Go version.
|
|
</p>
|
|
<div class="highlight highlight-source-dockerfile">
|
|
<pre><span class="pl-k">WORKDIR</span> /build
|
|
|
|
<span class="pl-k">COPY</span> go.mod .
|
|
<span class="pl-k">COPY</span> go.sum .
|
|
<span class="pl-k">COPY</span> vendor .
|
|
<span class="pl-k">COPY</span> . .</pre>
|
|
</div>
|
|
<p>
|
|
I use <code>/build</code> to emphasize that I am building something in
|
|
that directory.
|
|
</p>
|
|
<p>
|
|
The 4 <code>COPY</code> lines are familiar if you use Go enough. First is
|
|
<code>go.mod</code> and <code>go.sum</code> because it defines Go modules.
|
|
The second is <code>vendor</code>, this is optional but I use it because I
|
|
don't want each time I build Dockerfile, I need to redownload Go modules.
|
|
</p>
|
|
<div class="highlight highlight-source-dockerfile">
|
|
<pre><span class="pl-k">RUN</span> CGO_ENABLED=0 GOOS=linux GOARCH=amd64 GOAMD64=v3 go build -o ./app -tags timetzdata -trimpath -ldflags=<span class="pl-s">"-s -w"</span> .</pre>
|
|
</div>
|
|
<p>This is where I build Go program.</p>
|
|
<ul>
|
|
<li>
|
|
<code>CGO_ENABLED=0</code> because I don't want to mess with C
|
|
libraries.
|
|
</li>
|
|
<li>
|
|
<code>GOOS=linux GOARCH=amd64</code> is easy to explain, Linux with
|
|
x86-64.
|
|
</li>
|
|
<li>
|
|
<code>GOAMD64=v3</code> is new since
|
|
<a href="https://go.dev/doc/go1.18#amd64" rel="nofollow">Go 1.18</a>, I
|
|
use v3 because I read about AMD64 version in
|
|
<a
|
|
href="https://gitlab.archlinux.org/archlinux/rfcs/-/blob/master/rfcs/0002-march.rst"
|
|
rel="nofollow"
|
|
>Arch Linux rfcs</a
|
|
>. TLDR's newer computers are already x86-64-v3.
|
|
</li>
|
|
<li>
|
|
<code>-tags timetzdata</code> to embed timezone database in case base
|
|
image does not have.
|
|
</li>
|
|
<li><code>-trimpath</code> to support reproduce build.</li>
|
|
<li><code>-ldflags="-s -w"</code> to strip debugging information.</li>
|
|
</ul>
|
|
<div class="highlight highlight-source-dockerfile">
|
|
<pre><span class="pl-k">FROM</span> gcr.io/distroless/base-debian11
|
|
|
|
<span class="pl-k">COPY</span> --from=builder /build/app /app
|
|
|
|
<span class="pl-k">ENTRYPOINT</span> [<span class="pl-s">"/app"</span>]</pre>
|
|
</div>
|
|
<p>Finally, I copy <code>app</code> to Distroless base image.</p>
|
|
<h2>
|
|
<a
|
|
id="user-content-thanks"
|
|
class="anchor"
|
|
aria-hidden="true"
|
|
href="#thanks"
|
|
><span aria-hidden="true" class="octicon octicon-link"></span></a
|
|
>Thanks
|
|
</h2>
|
|
<ul>
|
|
<li>
|
|
<a
|
|
href="https://boyter.org/posts/how-to-start-go-project-2023/"
|
|
rel="nofollow"
|
|
>How to start a Go project in 2023</a
|
|
>
|
|
</li>
|
|
<li>
|
|
<a
|
|
href="https://words.filippo.io/shrink-your-go-binaries-with-this-one-weird-trick/"
|
|
rel="nofollow"
|
|
>Shrink your Go binaries with this one weird trick</a
|
|
>
|
|
</li>
|
|
</ul>
|
|
|
|
<div>
|
|
Feel free to ask me via
|
|
<a href="mailto:hauvipapro+posts@gmail.com">email</a> or
|
|
<a rel="me" href="https://hachyderm.io/@haunguyen">Mastodon</a>. Source
|
|
code is available on
|
|
<a href="https://github.com/haunt98/posts-go">GitHub</a>
|
|
</div>
|
|
</body>
|
|
</html>
|