Full Blog TOC

Full Blog Table Of Content with Keywords Available HERE

Sunday, February 26, 2023

Go Docker Build with Internal Shared Package

 


In the post Go Shared Library, we have reviewed a method to use a shared Go library in a single git repository. This is a case where we have multiple Go libraries in a single git repository, and some share libraries that are used by the modules. A possible folders structure for this use case is:



In this example, we have 3 modules and 2 common libraries. 

The go.mod file for module-a, includes the replace section for the internal shared libraries.


module my.company.com/example/modulea

go 1.19

replace (
my.company.com/example/commonlib1 => ../common-lib-1
my.company.com/example/commonlib2 => ../common-lib-2
)

require (
my.company.com/example/commonlib1 v0.0.0-00010101000000-000000000000
my.company.com/example/commonlib2 v0.0.0-00010101000000-000000000000
)


To build a docker image for this module, we need to add the sources of all the requirements. We can do it manually for each of module-a, module-b, and module-c. A better approach is to automatically handle this. 

We present now a script to automatically build a docker image for a Go module, including the internal module source includes. This automation is done based on the parsing of the related module go.mod file.



#!/usr/bin/env bash

#-------------------------------------
# This script builds a single GO image
#-------------------------------------

set -e

DockerRegistry="${DockerRegistry:-my-project-snapshot-local}"
ProjectVersion="${ProjectVersion:-/dev:latest}"
ScriptsFolder=$(dirname "$0")
Project=$(basename ${PWD})
EntryPoint=\\/${Project}
ArtifactName="my-project-${FolderName}"
DockerTag="${DockerRegistry}/my-project-${Project}${ProjectVersion}"


AddKubectl=false
PushImage=false

HandleCommonPackage(){
commonPackage=$1
sourceFolder=$(echo "${commonPackage}" | cut -c 9-)

echo "common module ${sourceFolder}"

if [[ ! -d ./temp-commons-go-manifest/${sourceFolder} ]]; then
mkdir -p ./temp-commons-go-manifest/${sourceFolder}
cp ../${sourceFolder}/go.mod ./temp-commons-go-manifest/${sourceFolder}/go.mod
cp ../${sourceFolder}/go.sum ./temp-commons-go-manifest/${sourceFolder}/go.sum
fi

if [[ ! -d ./temp-commons-go-all/${sourceFolder} ]]; then
mkdir -p ./temp-commons-go-all/${sourceFolder}
sourceParent=$(dirname ./temp-commons-go-all/${sourceFolder})
cp -r ../${sourceFolder} ${sourceParent}
fi
}

ReplaceVariables(){
sed -i "s/___PROJECT___/${Project}/g" temp-Dockerfile
sed -i "s/___ENTRYPOINT___/${EntryPoint}/g" temp-Dockerfile

grep "=" ./src/go.mod | cut -d= -f2 | while read line ; do HandleCommonPackage "$line" ; done
}

CleanTemp(){
rm -f temp-Dockerfile
rm -rf ./temp-commons-go-manifest
rm -rf ./temp-commons-go-all
}

Build(){
CleanTemp
mkdir ./temp-commons-go-manifest
mkdir ./temp-commons-go-all

cat ${ScriptsFolder}/Dockerfile_stage1 >> temp-Dockerfile
ReplaceVariables
echo "COPY files /images/${Project}/files" >> temp-Dockerfile
echo "RUN go test -race -timeout 300s ./..." >> temp-Dockerfile

TagCompileStage="${DockerTag}-stage1"
docker build -t "${DockerTag}" -c ${TagCompileStage} --cache-from=${DockerTag} -f temp-Dockerfile

cat ${ScriptsFolder}/Dockerfile_stage2 >> temp-Dockerfile
ReplaceVariables

if [[ -d files ]]; then
echo "COPY files /" >> temp-Dockerfile
fi

docker build -t "${DockerTag}" -c ${TagCompileStage} --cache-from=${DockerTag} -f temp-Dockerfile

CleanTemp
}

Build


The script uses a two-stages build. These stages docker files templates located in Dockerfile_stage1, and Dockerfile_stage2. Notice that the script automatically replaces ___VARIABLE___ strings in the docker file.


Dockerfile_stage1

FROM golang:1.19.1 AS go-compiler

ENV GOPATH=/go GOBIN=/go/bin

# get dependencies
COPY ./src/go.mod /images/___PROJECT___/src/
COPY ./src/go.sum /images/___PROJECT___/src/
ADD ./temp-commons-go-manifest /images
WORKDIR /images/___PROJECT___/src

RUN go mod download

# compile source
ADD ./src /images/___PROJECT___/src
ADD ./temp-commons-go-all /images

RUN go build -o /output/___PROJECT___


Dockerfile_stage2

FROM ubuntu:20.04
RUN apt update
RUN apt install -y net-tools ca-certificates curl iputils-ping dnsutils
RUN update-ca-certificates

COPY --from=go-compiler /output/___PROJECT___ /___PROJECT___
WORKDIR /
ENTRYPOINT ["___ENTRYPOINT___"]



Final Note


Using this simple script, handling of the docker image creation is automatic and simple. It is a great tool to automate Go modules and Go internal libraries usage.




No comments:

Post a Comment