From ca966b71966b29b1cd2b2123a305ca998a436838 Mon Sep 17 00:00:00 2001
From: Malte Bauch <malte.bauch@tbnet.works>
Date: Thu, 30 Jun 2022 10:16:11 +0000
Subject: [PATCH] Fix: Improve Dockerfiles and containerlab creation
 (especially in build and startup time)

See merge request danet/gosdn!341

Co-authored-by: Malte Bauch <malte.bauch@extern.h-da.de>
---
 .gitlab/ci/.build-container.yml               |  4 +-
 Makefile                                      | 37 ++++++++++++++-----
 cli/Dockerfile                                | 20 ----------
 cli/cli.Dockerfile                            | 17 +++++++++
 cli/cli.Dockerfile.dockerignore               | 17 +++++++++
 controller/Dockerfile                         | 18 ---------
 controller/Makefile                           |  6 +--
 controller/controller.Dockerfile              | 18 +++++++++
 controller/controller.Dockerfile.dockerignore | 17 +++++++++
 controller/nucleus/plugin.go                  |  1 +
 csbi/{Dockerfile => csbi.Dockerfile}          | 20 +++++-----
 csbi/csbi.Dockerfile.dockerignore             | 17 +++++++++
 .../{Dockerfile => gnmitarget.Dockerfile}     |  0
 .../gnmitarget.Dockerfile.dockerignore        | 21 +++++++++++
 14 files changed, 151 insertions(+), 62 deletions(-)
 delete mode 100644 cli/Dockerfile
 create mode 100644 cli/cli.Dockerfile
 create mode 100644 cli/cli.Dockerfile.dockerignore
 delete mode 100644 controller/Dockerfile
 create mode 100644 controller/controller.Dockerfile
 create mode 100644 controller/controller.Dockerfile.dockerignore
 rename csbi/{Dockerfile => csbi.Dockerfile} (60%)
 create mode 100644 csbi/csbi.Dockerfile.dockerignore
 rename csbi/gnmi-target/{Dockerfile => gnmitarget.Dockerfile} (100%)
 create mode 100644 csbi/gnmi-target/gnmitarget.Dockerfile.dockerignore

diff --git a/.gitlab/ci/.build-container.yml b/.gitlab/ci/.build-container.yml
index a2a782b8b..aa4fc2c1e 100644
--- a/.gitlab/ci/.build-container.yml
+++ b/.gitlab/ci/.build-container.yml
@@ -9,14 +9,14 @@
 build-testing-image:
     script:
         - docker login -u $CI_REGISTRY_USER -p $CI_REGISTRY_PASSWORD $CI_REGISTRY
-        - docker build -t "$GOSDN_TESTING_IMAGE" -f "${CI_PROJECT_DIR}/controller/Dockerfile" --target "installer" --build-arg "GOLANG_VERSION=$GOLANG_VERSION" --build-arg "BUILDARGS=$BUILDARGS" --build-arg "GITLAB_PROXY=${CI_DEPENDENCY_PROXY_GROUP_IMAGE_PREFIX}/" .
+        - docker buildx build -t "$GOSDN_TESTING_IMAGE" -f "${CI_PROJECT_DIR}/controller/controller.Dockerfile" --target "builder" --build-arg "GOLANG_VERSION=$GOLANG_VERSION" --build-arg "BUILDARGS=$BUILDARGS" --build-arg "GITLAB_PROXY=${CI_DEPENDENCY_PROXY_GROUP_IMAGE_PREFIX}/" .
         - docker push "$GOSDN_TESTING_IMAGE"
     <<: *build
 
 build-image:
     script:
         - docker login -u $CI_REGISTRY_USER -p $CI_REGISTRY_PASSWORD $CI_REGISTRY
-        - docker build -t "$CI_REGISTRY_IMAGE:$TAG" -f "${CI_PROJECT_DIR}/controller/Dockerfile" --build-arg "GOLANG_VERSION=$GOLANG_VERSION" --build-arg "BUILDARGS=$BUILDARGS" --build-arg "GITLAB_PROXY=${CI_DEPENDENCY_PROXY_GROUP_IMAGE_PREFIX}/" .
+        - docker buildx build -t "$CI_REGISTRY_IMAGE:$TAG" -f "${CI_PROJECT_DIR}/controller/controller.Dockerfile" --build-arg "GOLANG_VERSION=$GOLANG_VERSION" --build-arg "BUILDARGS=$BUILDARGS" --build-arg "GITLAB_PROXY=${CI_DEPENDENCY_PROXY_GROUP_IMAGE_PREFIX}/" .
         - docker push "$CI_REGISTRY_IMAGE:$TAG"
         # replace all slashes in the tag with hyphen, because slashes are not allowed in tags
         - NEWTAG=${CI_COMMIT_BRANCH//\//-}
diff --git a/Makefile b/Makefile
index 32c585e98..b21e5071d 100644
--- a/Makefile
+++ b/Makefile
@@ -52,32 +52,49 @@ generate-csbi-yang-models: install-tools
 	../../$(TOOLS_DIR)/go-ygot-generator-generator config.yaml gostructs.go &&\
 	go generate
 
-build: pre
-	$(GOBUILD) -o $(BUILD_ARTIFACTS_PATH)/gosdn ./controller/cmd/gosdn
+build: pre build-gosdn build-gosdnc build-orchestrator
+
+build-gosdn: pre
+	$(GOBUILD) -trimpath -o $(BUILD_ARTIFACTS_PATH)/gosdn ./controller/cmd/gosdn
+
+build-gosdnc: pre
 	CGO_ENABLED=0 $(GOBUILD) -o $(BUILD_ARTIFACTS_PATH)/gosdnc ./cli/
+
+build-orchestrator: pre
 	CGO_ENABLED=0 $(GOBUILD) -o $(BUILD_ARTIFACTS_PATH)/orchestrator ./csbi/cmd/csbi/
 
-start: build
-	./$(BUILD_ARTIFACTS_PATH)/gosdn -l debug --config ./controller/configs/gosdn.toml
+containerize-all: containerize-gosdn containerize-gosdnc containerize-orchestrator containerize-target
+
+containerize-gosdn:
+	docker buildx build --rm -t gosdn -f controller/controller.Dockerfile .
+
+containerize-gosdnc:
+	docker buildx build --rm -t gosdnc -f cli/cli.Dockerfile .
 
-container: build
-	docker build -t gosdn -f controller/Dockerfile .
-	docker build -t gosdnc -f cli/Dockerfile .
-	docker build -t orchestrator -f csbi/Dockerfile .
-	docker build -t gnmi-target -f csbi/gnmi-target/Dockerfile .
+containerize-orchestrator:
+	docker buildx build --rm -t orchestrator -f csbi/csbi.Dockerfile .
 
-containerlab-start: container
+containerize-target:
+	docker buildx build --rm -t gnmi-target -f csbi/gnmi-target/gnmitarget.Dockerfile .
+
+containerlab-start: containerize-all
 	sudo containerlab deploy --topo gosdn.clab.yaml
+
 containerlab-stop:
 	sudo containerlab destroy --topo gosdn.clab.yaml
+
 containerlab-graph:
 	sudo containerlab graph --topo gosdn.clab.yaml
 
 shell-gosdn:
 	docker exec -it clab-gosdn_csbi_arista_base-gosdn bash
+
 shell-orchestrator:
 	docker exec -it clab-gosdn_csbi_arista_base-orchestrator bash
 
+start: build-gosdn
+	./$(BUILD_ARTIFACTS_PATH)/gosdn -l debug --config ./controller/configs/gosdn.toml
+
 clean:
 	$(GOCLEAN)
 	rm -rf $(BUILD_ARTIFACTS_PATH)
diff --git a/cli/Dockerfile b/cli/Dockerfile
deleted file mode 100644
index 873bf8d72..000000000
--- a/cli/Dockerfile
+++ /dev/null
@@ -1,20 +0,0 @@
-ARG GOLANG_VERSION=1.18
-ARG BUILDARGS
-ARG $GITLAB_PROXY
-
-FROM ${GITLAB_PROXY}golang:$GOLANG_VERSION-buster AS installer
-
-WORKDIR /gosdn/
-COPY go.* ./
-RUN go mod download
-
-FROM installer as builder
-COPY . .
-RUN make build
-
-
-FROM scratch as gosdnc
-
-COPY --from=builder  /gosdn/artifacts/gosdnc /
-
-ENTRYPOINT ["/gosdnc"]
diff --git a/cli/cli.Dockerfile b/cli/cli.Dockerfile
new file mode 100644
index 000000000..5787b7480
--- /dev/null
+++ b/cli/cli.Dockerfile
@@ -0,0 +1,17 @@
+ARG GOLANG_VERSION=1.18
+ARG BUILDARGS
+ARG $GITLAB_PROXY
+
+FROM ${GITLAB_PROXY}golang:$GOLANG_VERSION-alpine AS builder
+WORKDIR /gosdn/
+RUN apk add build-base
+COPY . .
+RUN --mount=type=cache,target=/root/go/pkg/mod \
+    --mount=type=cache,target=/root/.cache/go-build \
+    make build-gosdnc
+
+FROM scratch as gosdnc
+
+COPY --from=builder /gosdn/artifacts/gosdnc /
+
+ENTRYPOINT ["./gosdnc"]
diff --git a/cli/cli.Dockerfile.dockerignore b/cli/cli.Dockerfile.dockerignore
new file mode 100644
index 000000000..5cd2977c8
--- /dev/null
+++ b/cli/cli.Dockerfile.dockerignore
@@ -0,0 +1,17 @@
+.git
+.gitlab
+build
+documentation
+mocks
+test
+clab-gosdn_csbi_arista_base
+.cobra.yaml
+*.dockerignore
+.gitlab-ci.yaml
+ARCHITECTURE.md
+CONTRIBUTING.md
+README.md
+artifacts
+build-tools
+models
+csbi
diff --git a/controller/Dockerfile b/controller/Dockerfile
deleted file mode 100644
index 0dd6c8756..000000000
--- a/controller/Dockerfile
+++ /dev/null
@@ -1,18 +0,0 @@
-ARG GOLANG_VERSION=1.18
-ARG BUILDARGS
-ARG $GITLAB_PROXY
-
-FROM ${GITLAB_PROXY}golang:$GOLANG_VERSION-buster AS installer
-
-WORKDIR /gosdn/
-COPY go.* ./
-RUN go mod download
-
-FROM installer as builder
-COPY . .
-RUN make build
-
-FROM builder as gosdn
-COPY controller/configs/development-gosdn.toml.example /gosdn/configs/development-gosdn.toml
-COPY controller/configs/containerlab-gosdn.toml.example /gosdn/configs/containerlab-gosdn.toml
-ENTRYPOINT ["/gosdn/artifacts/gosdn"]
diff --git a/controller/Makefile b/controller/Makefile
index b06c7ba44..172b33e0d 100644
--- a/controller/Makefile
+++ b/controller/Makefile
@@ -36,16 +36,16 @@ start-insecure: clean build
 	ENVIRONMENT=development ./$(BINARY_NAME) -l debug -s insecure
 
 unit-test: install-tools
-	ENVIRONMENT=testing ./$(TOOLS_DIR)/gotestsum --junitfile report.xml --format testname -- -short -race $$( go list ./... | grep -v /forks/ | grep -v /mocks ) -v -coverprofile=coverage.out
+	ENVIRONMENT=testing ./$(TOOLS_DIR)/gotestsum --junitfile report.xml --format testname -- -short -race $$( go list ./... | grep -v /forks/ | grep -v /mocks ) -v -trimpath -coverprofile=coverage.out
 
 controller-test: install-tools
 	ENVIRONMENT=testing ./$(TOOLS_DIR)/gotestsum --junitfile report.xml --format testname -- -race -v -run TestRun
 
 ci-unit-test: ci-install-tools
-	ENVIRONMENT=testing gotestsum --junitfile report.xml --format testname -- -short -race $$( go list ./... | grep -v /forks/ | grep -v /mocks ) -v -coverprofile=coverage.out -covermode atomic -timeout 30m
+	ENVIRONMENT=testing gotestsum --junitfile report.xml --format testname -- -short -race $$( go list ./... | grep -v /forks/ | grep -v /mocks ) -v -trimpath -coverprofile=coverage.out -covermode atomic -timeout 30m
 
 ci-controller-test: ci-install-tools
-	ENVIRONMENT=testing gotestsum --junitfile report.xml --format testname -- -race -v -run TestRun -coverprofile=coverage.out
+	ENVIRONMENT=testing gotestsum --junitfile report.xml --format testname -- -race -v -run TestRun -trimpath -coverprofile=coverage.out
 
 integration-test-nucleus:
 	ENVIRONMENT=testing  &&\
diff --git a/controller/controller.Dockerfile b/controller/controller.Dockerfile
new file mode 100644
index 000000000..344d7975d
--- /dev/null
+++ b/controller/controller.Dockerfile
@@ -0,0 +1,18 @@
+ARG GOLANG_VERSION=1.18
+ARG BUILDARGS
+ARG $GITLAB_PROXY
+
+FROM ${GITLAB_PROXY}golang:$GOLANG_VERSION-alpine as builder
+WORKDIR /gosdn/
+RUN apk add --no-cache build-base
+RUN apk add --no-cache bash
+COPY . .
+RUN --mount=type=cache,target=/root/go/pkg/mod \
+    --mount=type=cache,target=/root/.cache/go-build \
+    make build-gosdn
+
+# NOTE: We probably want to make this smaller
+FROM builder as gosdn
+COPY controller/configs/development-gosdn.toml.example ./configs/development-gosdn.toml
+COPY controller/configs/containerlab-gosdn.toml.example ./configs/containerlab-gosdn.toml
+ENTRYPOINT ["./artifacts/gosdn"]
diff --git a/controller/controller.Dockerfile.dockerignore b/controller/controller.Dockerfile.dockerignore
new file mode 100644
index 000000000..111383275
--- /dev/null
+++ b/controller/controller.Dockerfile.dockerignore
@@ -0,0 +1,17 @@
+.git
+.gitlab
+build
+documentation
+mocks
+test
+clab-gosdn_csbi_arista_base
+.cobra.yaml
+.dockeringore
+.gitlab-ci.yaml
+ARCHITECTURE.md
+CONTRIBUTING.md
+README.md
+artifacts
+build-tools
+models/YangModels
+models/arista
diff --git a/controller/nucleus/plugin.go b/controller/nucleus/plugin.go
index a2efabefb..82e65626f 100644
--- a/controller/nucleus/plugin.go
+++ b/controller/nucleus/plugin.go
@@ -27,6 +27,7 @@ func BuildPlugin(path string, sourceFileNames []string, args ...string) error {
 		"go",
 		"build",
 		"-buildmode=plugin",
+		"-trimpath",
 		"-o",
 		pPath,
 	}
diff --git a/csbi/Dockerfile b/csbi/csbi.Dockerfile
similarity index 60%
rename from csbi/Dockerfile
rename to csbi/csbi.Dockerfile
index 01787be8f..b853e90c8 100644
--- a/csbi/Dockerfile
+++ b/csbi/csbi.Dockerfile
@@ -2,17 +2,19 @@ ARG GOLANG_VERSION=1.18
 ARG BUILDARGS
 ARG $GITLAB_PROXY
 
-FROM ${GITLAB_PROXY}golang:$GOLANG_VERSION-buster AS installer
-
+FROM ${GITLAB_PROXY}golang:$GOLANG_VERSION-alpine AS builder
 WORKDIR /gosdn/
+RUN apk add build-base
+COPY ./models ./models
+COPY ./forks ./forks
+COPY ./Makefile .
+COPY ./api ./api
+COPY ./controller ./controller
+COPY ./csbi ./csbi
 COPY go.* ./
-RUN go mod download
-
-FROM installer as builder
-
-COPY . .
-
-RUN make build
+RUN --mount=type=cache,target=/root/go/pkg/mod \
+    --mount=type=cache,target=/root/.cache/go-build \
+    make build-orchestrator
 
 FROM ${GITLAB_PROXY}golang:$GOLANG_VERSION-alpine
 RUN apk add --no-cache git make build-base
diff --git a/csbi/csbi.Dockerfile.dockerignore b/csbi/csbi.Dockerfile.dockerignore
new file mode 100644
index 000000000..bc153b70b
--- /dev/null
+++ b/csbi/csbi.Dockerfile.dockerignore
@@ -0,0 +1,17 @@
+.git
+.gitlab
+build
+documentation
+mocks
+test
+clab-gosdn_csbi_arista_base
+.cobra.yaml
+.dockeringore
+.gitlab-ci.yaml
+ARCHITECTURE.md
+CONTRIBUTING.md
+README.md
+artifacts
+build-tools
+models/YangModels/vendor
+models/YangModels/experimental
diff --git a/csbi/gnmi-target/Dockerfile b/csbi/gnmi-target/gnmitarget.Dockerfile
similarity index 100%
rename from csbi/gnmi-target/Dockerfile
rename to csbi/gnmi-target/gnmitarget.Dockerfile
diff --git a/csbi/gnmi-target/gnmitarget.Dockerfile.dockerignore b/csbi/gnmi-target/gnmitarget.Dockerfile.dockerignore
new file mode 100644
index 000000000..4e9a6933c
--- /dev/null
+++ b/csbi/gnmi-target/gnmitarget.Dockerfile.dockerignore
@@ -0,0 +1,21 @@
+.git
+.gitlab
+build
+documentation
+mocks
+test
+clab-gosdn_csbi_arista_base
+.cobra.yaml
+*.dockerignore
+.gitlab-ci.yaml
+ARCHITECTURE.md
+CONTRIBUTING.md
+README.md
+artifacts
+build-tools
+models
+cli
+controller
+api
+scripts
+forks
-- 
GitLab