diff --git a/.dockerignore b/.dockerignore new file mode 100644 index 0000000..8dc8322 --- /dev/null +++ b/.dockerignore @@ -0,0 +1,6 @@ +LICENSE +dockerfile +makefile +.makeVars +*.md +*.sh diff --git a/config.yaml.example b/config.yaml.example new file mode 100644 index 0000000..91db3ed --- /dev/null +++ b/config.yaml.example @@ -0,0 +1,4 @@ +--- +listen: + address: 0.0.0.0 + port: 80 diff --git a/deploy.sh b/deploy.sh new file mode 100644 index 0000000..1376042 --- /dev/null +++ b/deploy.sh @@ -0,0 +1,39 @@ +#!/usr/bin/env bash + +# Convert deployment paths into array +ENVIRONMENTS=($DEPLOYMENT_PATHS) + +# Check if the DEPLOYMENT_PATH is not already set +if [ -z "${DEPLOYMENT_PATH}" ]; then + # Print and ask for deployment environment (if more than one) + if [ "${#ENVIRONMENTS[@]}" -gt 1 ]; then + for i in "${!ENVIRONMENTS[@]}"; do + echo "$i: ${ENVIRONMENTS[$i]}" + done + read -p "Deployment environment: " DEPLOYMENT_ENVIRONMENT + fi + if [ -z "${DEPLOYMENT_ENVIRONMENT}" ]; then + DEPLOYMENT_ENVIRONMENT=0 + fi + # Select correct path + DEPLOYMENT_PATH="${ENVIRONMENTS[$DEPLOYMENT_ENVIRONMENT]}" +fi + +# Check if the DEPLOYMENT_VERSION is not already set +if [ -z "${DEPLOYMENT_VERSION}" ]; then + # Ask for deployment version + read -p "Version [latest]: " DEPLOYMENT_VERSION + if [ -z "${DEPLOYMENT_VERSION}" ]; then + DEPLOYMENT_VERSION=latest + fi +fi + +echo "${DEPLOYMENT_PATH}" +echo "${DEPLOYMENT_VERSION}" + +ssh $DEPLOYMENT_HOST \ + "cd ${DEPLOYMENT_PATH} && \ + git pull && \ + sed -i "s/VERSION=.*/VERSION=${DEPLOYMENT_VERSION}/" .env && \ + docker compose pull && \ + docker compose up -d" diff --git a/dockerfile b/dockerfile new file mode 100644 index 0000000..1084547 --- /dev/null +++ b/dockerfile @@ -0,0 +1,33 @@ +# Stage 1 · go builder +ARG GO_BUILDER=golang +ARG GO_VERSION=latest +FROM ${GO_BUILDER}:${GO_VERSION} AS build + +ARG GO_OS +ARG GO_ARCH +ARG GIT_HOST +ARG REPO_ORG +ARG REPO_NAME +ARG APP_VERSION + +# Copy the project inside the builder container +WORKDIR $GOPATH/src/${GIT_HOST}/$REPO_ORG/$REPO_NAME/ +COPY . . + +# Build the binary +RUN CGO_ENABLED=0 GOOS=${GO_OS} GOARCH=${GO_ARCH} \ + go build \ + -installsuffix cgo \ + -ldflags="-w -s -X 'main.APP_VERSION=${APP_VERSION}' -X 'main.COMMIT_ID=$(git log HEAD --oneline | awk '{print $1}' | head -n1)'" \ + --o /app + +# Stage 2 · scratch image +FROM scratch + +# Copy the necessary stuff from the build stage +COPY --from=build /app /app +# Copy the certificates - in case of fetches +COPY --from=build /etc/ssl/certs/ca-certificates.crt /etc/ssl/cert.pem + +# Execute the binary +ENTRYPOINT ["/app"] diff --git a/main.go b/main.go new file mode 100644 index 0000000..d089051 --- /dev/null +++ b/main.go @@ -0,0 +1,42 @@ +package main + +import ( + "context" + "fmt" + "os" + "os/signal" + "syscall" + "time" +) + +var APP_VERSION string = "latest" +var COMMIT_ID string = "undefined" +var ws *WebServer + +func main() { + // Create a channel to receive the OS signals + sc := make(chan os.Signal, 1) + signal.Notify(sc, syscall.SIGINT, syscall.SIGTERM) + + // Initialize the WebService structure + ws = new(WebServer) + ws.Initialize() + + // Start the WebService + go ws.Start() + + // Wait for a signal + <-sc + fmt.Println("Shutting down...") + + // Create a context with a timeout for graceful shutdown + shCtx, shCancel := context.WithTimeout(context.Background(), 5*time.Second) + defer shCancel() + + // Shutdown the HTTP server + err := ws.HTTPServer.Shutdown(shCtx) + if err != nil { + fmt.Printf("Server shutdown error: %s", err) + os.Exit(1) + } +} diff --git a/makefile b/makefile new file mode 100644 index 0000000..4458508 --- /dev/null +++ b/makefile @@ -0,0 +1,54 @@ +#!make +include .vars + +default: version + +clean: + if [ "$$(docker images "$${CONTAINER_ORG}/$${CONTAINER_IMAGE}" --format "{{.Repository}}:{{.Tag}}")" != "" ]; then \ + docker image rm $$(docker images "$${CONTAINER_ORG}/$${CONTAINER_IMAGE}" --all --format "{{.Repository}}:{{.Tag}}"); \ + fi + +docker: clean + docker build \ + --build-arg GO_BUILDER=$${GO_BUILDER} \ + --build-arg GO_VERSION=$${GO_VERSION} \ + --build-arg GO_OS=$${GO_OS} \ + --build-arg GO_ARCH=$${GO_ARCH} \ + --build-arg GIT_HOST=$${GIT_HOST} \ + --build-arg REPO_ORG=$${REPO_ORG} \ + --build-arg REPO_NAME=$${REPO_NAME} \ + --build-arg APP_VERSION=$${APP_VERSION} \ + -t $${CONTAINER_ORG}/$${CONTAINER_IMAGE}:$${APP_VERSION} .; \ + if [ "$$(docker images --filter "dangling=true" --quiet --no-trunc)" != "" ]; then \ + docker image rm $$(docker images --filter "dangling=true" --quiet --no-trunc); \ + fi + +dockerpush: + docker push \ + $${CONTAINER_ORG}/$${CONTAINER_IMAGE}:$${APP_VERSION} + +deploy: + bash -c "./deploy.sh" + +version: + bash -c "./version.sh" + +run: + docker run \ + --rm \ + --tty \ + --interactive \ + --publish $${CONTAINER_IP}:$${CONTAINER_PORT}:80 \ + --workdir /go/src/$${GIT_HOST}/$${REPO_ORG}/$${REPO_NAME} \ + --volume $(shell pwd):/go/src/$${GIT_HOST}/$${REPO_ORG}/$${REPO_NAME} \ + $${GO_BUILDER}:$${GO_VERSION} \ + go run . + +dockerrun: + docker run \ + --rm \ + --tty \ + --interactive \ + --publish $${CONTAINER_IP}:$${CONTAINER_PORT}:80 \ + --volume $(shell pwd)/config.yml:/config.yml \ + $${CONTAINER_ORG}/$${CONTAINER_IMAGE}:latest diff --git a/routes.go b/routes.go new file mode 100644 index 0000000..eedf5b6 --- /dev/null +++ b/routes.go @@ -0,0 +1,7 @@ +package main + +import "github.com/gorilla/mux" + +func (s *WebServer) Routes(r *mux.Router) { + r.HandleFunc("/version", handleVersion).Methods("GET") +} diff --git a/templates/html/version.html b/templates/html/version.html new file mode 100644 index 0000000..e4f30ee --- /dev/null +++ b/templates/html/version.html @@ -0,0 +1,12 @@ + + +
+
+ Version: {{.Version}}
+ Commit ID: {{.CommitId}}
+