Golang Installation #
Windows #
Install Golang (Winget) #
# Install Golang with Winget
winget install GoLang.Go
Verify Installation #
# Verify installation / check version
go version
Linux (Debian based) #
Install Binary #
# Change directory
cd /tmp
# Download package
wget https://go.dev/dl/go1.21.8.linux-amd64.tar.gz
# Install Go (Removes old Go packages)
sudo sh -c 'rm -rf /usr/local/go && tar -C /usr/local -xzf *.tar.gz'
Export Path Variable #
Temporary:
# Add binary to the PATH environment variable
export PATH=$PATH:/usr/local/go/bin
Permanent:
# Append to .bashrc of current user
echo 'export PATH=$PATH:/usr/local/go/bin' >> ~/.bashrc
# Reload the .bashrc / apply the changes
source ~/.bashrc
Verify Installation #
# Verify installation / check version
go version
Example: Hello World #
This is the most basic version to run and compile some Go code.
Program Code #
# Create a .go file
vi helloworld.go
// Declare the main package / required for any standalone executable Go program
package main
// Import the fmt package for formatted input/output functions
import "fmt"
// Define the main function, the entry point of the program
func main() {
fmt.Println("Hi there!") // Print the message to the console
}
Run Application #
# Run application
go run helloworld.go
# Shell output:
Hi there!
Compile & Run Application #
# Compile Go file into an executable binary
go build helloworld.go
# Run the executable binary
./helloworld
# Shell output:
Hi there!
Example: Hello World Webserver Project #
The goal of this code is to deploy a web server that is as simple as possible, just to get a feeling for the dependencies and how to containerize a Go application.
Project Directory #
# Create a directory for the new project
mkdir some-go-project && cd some-go-project
Init Project #
# Initialize the project
go mod init jueklu/some-go-project
# Shell output:
go: creating new go.mod: module jueklu/some-go-project
Verify go.mod #
The go mod init
command has created a go.mod
file, where Go tracks the project dependencies.
# Cat the go.mod file
cat go.mod
# Shell output:
module jueklu/some-go-project
go 1.21.8
Program Code #
Go Application:
# Create a .go file
vi helloworld.go
// Declare the main package / required for any standalone executable Go program
package main
import (
"github.com/gin-gonic/contrib/static"
"github.com/gin-gonic/gin"
)
func main() {
r := gin.Default()
// Serve static files from the "./views" directory
r.Use(static.Serve("/", static.LocalFile("./views", true)))
// Start the server on the default port (8080)
r.Run()
}
Website:
# Create a directory for the website
mkdir views
# Create a index.html file
vi views/index.html
<!DOCTYPE html>
<html>
<head>
<title>jklug.work</title>
</head>
<body>
<h1>Hi there</h1>
</body>
</html>
Run Application / Add Dependencies #
Run Go Application #
# Run application
go run helloworld.go
# Shell output:
helloworld.go:5:2: no required module provides package github.com/gin-gonic/contrib/static; to add it:
go get github.com/gin-gonic/contrib/static
helloworld.go:6:2: no required module provides package github.com/gin-gonic/gin; to add it:
go get github.com/gin-gonic/gin
Add Dependencies #
# Add the missing dependencies
go get github.com/gin-gonic/contrib/static
go get github.com/gin-gonic/gin
Verify go.mod #
Verify the go.mod file again:
# Cat the go.mod file
cat go.mod
# Shell output:
module jueklu/some-go-project
go 1.21.8
require (
github.com/bytedance/sonic v1.11.6 // indirect
github.com/bytedance/sonic/loader v0.1.1 // indirect
github.com/cloudwego/base64x v0.1.4 // indirect
github.com/cloudwego/iasm v0.2.0 // indirect
github.com/gabriel-vasile/mimetype v1.4.3 // indirect
github.com/gin-contrib/sse v0.1.0 // indirect
github.com/gin-gonic/contrib v0.0.0-20240508051311-c1c6bf0061b0 // indirect
github.com/gin-gonic/gin v1.10.0 // indirect
github.com/go-playground/locales v0.14.1 // indirect
github.com/go-playground/universal-translator v0.18.1 // indirect
github.com/go-playground/validator/v10 v10.20.0 // indirect
github.com/goccy/go-json v0.10.2 // indirect
github.com/json-iterator/go v1.1.12 // indirect
github.com/klauspost/cpuid/v2 v2.2.7 // indirect
github.com/leodido/go-urn v1.4.0 // indirect
github.com/mattn/go-isatty v0.0.20 // indirect
github.com/modern-go/concurrent v0.0.0-20180306012644-bacd9c7ef1dd // indirect
github.com/modern-go/reflect2 v1.0.2 // indirect
github.com/pelletier/go-toml/v2 v2.2.2 // indirect
github.com/twitchyliquid64/golang-asm v0.15.1 // indirect
github.com/ugorji/go/codec v1.2.12 // indirect
golang.org/x/arch v0.8.0 // indirect
golang.org/x/crypto v0.23.0 // indirect
golang.org/x/net v0.25.0 // indirect
golang.org/x/sys v0.20.0 // indirect
golang.org/x/text v0.15.0 // indirect
google.golang.org/protobuf v1.34.1 // indirect
gopkg.in/yaml.v3 v3.0.1 // indirect
)
Run Go Application #
Run the application again
# Run application
go run helloworld.go
# Verify the webserver (Open new shell)
curl localhost:8080
# Shell output:
<!DOCTYPE html>
<html>
<head>
<title>jklug.work</title>
</head>
Stop the GO application: Strg
+ c
Verify go.sum File #
A go.sum file should now be available:
# List GO project files
ls
# Shell output:
go.mod go.sum helloworld.go
Compile & Run Application #
# Compile Go file into an executable binary
go build helloworld.go
Run the Binary:
# Run the executable binary
./helloworld
# Curl the application (In new shell)
curl localhost:8080
Multistage Docker Build #
Create a Docker container of the previous “Hello World Webserver Project” example.
Dockerfile #
# Create a Dockerfile
vi Dockerfile
### Stage 1: Compile Binary
# Start from Golang Alpine base image / Label image as "builder"
FROM golang:1.23.3-alpine AS builder
# Create build directory
RUN mkdir /build
# Add GO files
ADD go.mod go.sum helloworld.go /build/
# Define working directory
WORKDIR /build
# Compile Go file into an executable binary
RUN go build -o helloworld
### Stage 2: Final Container
# Start from Alpine base image
FROM alpine:latest
# Creates system user "appuser" / no PW
RUN adduser -S -D -H -h /app appuser
# Switch to "appuser"
USER appuser
# Copy "helloworld" binary from the "compile" stage to the "/app" directory in the container
COPY --from=builder /build/helloworld /app/
# Copy "views" directory from the build context (host) into "/app/views" in the container
COPY views/ /app/views
# Define working directory
WORKDIR /app
# Expose port 8080 for the application
EXPOSE 8080
# Execute the Go binary when the container starts
ENTRYPOINT ["./helloworld"]
Adduser:
-
-S
Create system account meant for running services or daemons -
D
Disables password creation for the user, making it a “no-login” account -
H
Prevents the creation of a home directory for the user -
h /app
Specifies “/app” as the home directory for the user -
appuser
The name of the user being created
Build Container Image #
# Build image named "helloworld" in from current directory
docker build -t helloworld .
# Verify the Docker image
docker images helloworld
# Shell output:
REPOSITORY TAG IMAGE ID CREATED SIZE
helloworld latest 75ecb65223bc 19 seconds ago 19.1MB
Create & Verify Container #
# Create a container from the "helloworld "image
docker run --rm -p 8080:8080 helloworld
# Verify the container (In new shell)
curl localhost:8080
Links #
# Download Golang package
https://go.dev/dl/
# Official Documentation
https://go.dev/doc/install
# gin-gonic / gin Web Framework
https://github.com/gin-gonic/gin