Skip to content
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
18 changes: 0 additions & 18 deletions .devcontainer/devcontainer.json

This file was deleted.

53 changes: 14 additions & 39 deletions Dockerfile
Original file line number Diff line number Diff line change
@@ -1,61 +1,36 @@
# syntax=docker/dockerfile:1

# -✂- this stage is used to develop and build the application locally -------------------------------------------------
FROM docker.io/library/golang:1.24-bookworm AS develop

# use the /var/tmp/go as the GOPATH to reuse the modules cache
ENV GOPATH="/var/tmp/go"

RUN set -x \
# renovate: source=github-releases name=golangci/golangci-lint
&& GOLANGCI_LINT_VERSION="2.3.0" \
&& wget -O- -nv "https://cdn.jsdelivr.net/gh/golangci/golangci-lint@v${GOLANGCI_LINT_VERSION}/install.sh" \
| sh -s -- -b /bin "v${GOLANGCI_LINT_VERSION}"

RUN set -x \
# customize the shell prompt (for the bash)
&& echo "PS1='\[\033[1;36m\][go] \[\033[1;34m\]\w\[\033[0;35m\] \[\033[1;36m\]# \[\033[0m\]'" >> /etc/bash.bashrc

WORKDIR /src

# burn the modules cache
RUN \
--mount=type=bind,source=go.mod,target=/src/go.mod \
--mount=type=bind,source=go.sum,target=/src/go.sum \
go mod download -x \
&& find "${GOPATH}" -type d -exec chmod 0777 {} \; \
&& find "${GOPATH}" -type f -exec chmod 0666 {} \;

# -✂- this stage is used to compile the application -------------------------------------------------------------------
FROM develop AS compile
FROM docker.io/library/golang:1.24-alpine AS compile

# can be passed with any prefix (like `v1.2.3@GITHASH`), e.g.: `docker build --build-arg "APP_VERSION=v1.2.3" .`
ARG APP_VERSION="undefined@docker"

# copy the source code
COPY . /src

WORKDIR /src

RUN set -x \
&& go generate ./... \
&& CGO_ENABLED=0 LDFLAGS="-s -w -X gh.tarampamp.am/error-pages/internal/appmeta.version=${APP_VERSION}" \
go build -trimpath -ldflags "${LDFLAGS}" -o /tmp/error-pages ./cmd/error-pages/ \
&& go generate -skip readme ./... \
&& CGO_ENABLED=0 go build \
-trimpath \
-ldflags "-s -w -X gh.tarampamp.am/error-pages/internal/appmeta.version=${APP_VERSION}" \
-o /tmp/error-pages \
./cmd/error-pages/ \
&& /tmp/error-pages --version \
&& /tmp/error-pages -h

# -✂- this stage is used to prepare the runtime fs --------------------------------------------------------------------
FROM docker.io/library/alpine:3.22 AS rootfs

WORKDIR /tmp/rootfs

# prepare rootfs for runtime
RUN set -x \
&& mkdir -p ./etc/ssl/certs ./bin \
&& echo 'appuser:x:10001:10001::/nonexistent:/sbin/nologin' > ./etc/passwd \
&& echo 'appuser:x:10001:' > ./etc/group \
&& cp /etc/ssl/certs/ca-certificates.crt ./etc/ssl/certs/

# take the binary from the compile stage
COPY --from=compile /tmp/error-pages ./bin/error-pages
&& cp /etc/ssl/certs/ca-certificates.crt ./etc/ssl/certs/ \
&& mv /tmp/error-pages ./bin/error-pages \
&& chmod 755 ./bin/error-pages

WORKDIR /tmp/rootfs/opt

Expand All @@ -81,7 +56,7 @@ LABEL \
org.opencontainers.image.licenses="MIT"

# import from builder
COPY --from=rootfs /tmp/rootfs /
COPY --from=compile /tmp/rootfs /

# use an unprivileged user
USER 10001:10001
Expand All @@ -95,7 +70,7 @@ ENV LOG_LEVEL="warn" \
LOG_FORMAT="json"

# docs: https://docs.docker.com/reference/dockerfile/#healthcheck
HEALTHCHECK --interval=10s --start-interval=1s --start-period=5s --timeout=2s CMD ["/bin/error-pages", "healthcheck"]
HEALTHCHECK --interval=10s --start-interval=1s --start-period=2s --timeout=1s CMD ["/bin/error-pages", "healthcheck"]

ENTRYPOINT ["/bin/error-pages"]

Expand Down
40 changes: 10 additions & 30 deletions Makefile
Original file line number Diff line number Diff line change
@@ -1,38 +1,18 @@
#!/usr/bin/make

DC_RUN_ARGS = --rm --user "$(shell id -u):$(shell id -g)"
.DEFAULT_GOAL : build

.DEFAULT_GOAL : help

help: ## Show this help
@printf "\033[33m%s:\033[0m\n" 'Available commands'
@awk 'BEGIN {FS = ":.*?## "} /^[a-zA-Z_-]+:.*?## / {printf " \033[32m%-11s\033[0m %s\n", $$1, $$2}' $(MAKEFILE_LIST)

.PHONY: up
up: ## Start the application in watch mode
docker compose kill web --remove-orphans 2>/dev/null || true
docker compose up --detach --wait web
$$SHELL -c "\
trap 'docker compose down --remove-orphans --timeout 30' EXIT; \
docker compose watch --no-up web \
"

.PHONY: down
down: ## Stop the application
docker compose down --remove-orphans
gen: ## Generate code
go generate ./...

.PHONY: shell
shell: ## Start shell into development environment
docker compose run -ti $(DC_RUN_ARGS) develop bash
build: gen ## Build the application
CGO_ENABLED=0 go build -trimpath -ldflags "-s -w" -o ./error-pages ./cmd/error-pages/

.PHONY: test
test: ## Run tests
docker compose run $(DC_RUN_ARGS) develop gotestsum --format pkgname -- -race -timeout 2m ./...
go test -race ./...

.PHONY: lint
lint: ## Run linters
docker compose run $(DC_RUN_ARGS) develop golangci-lint run
lint: ## Run linters (requires https://github.com/golangci/golangci-lint installed)
golangci-lint run

.PHONY: gen
gen: ## Generate code
docker compose run $(DC_RUN_ARGS) develop go generate ./...
up: build ## Start the application at http://localhost:8080
./error-pages --log-level debug serve --show-details --proxy-headers=X-Foo,Bar,Baz_blah
11 changes: 7 additions & 4 deletions cmd/error-pages/main.go
Original file line number Diff line number Diff line change
Expand Up @@ -6,18 +6,19 @@ import (
"os"
"os/signal"
"path/filepath"
"runtime"
"syscall"

"go.uber.org/automaxprocs/maxprocs"

"gh.tarampamp.am/error-pages/internal/cli"
)

// set GOMAXPROCS to match Linux container CPU quota.
var _, _ = maxprocs.Set(maxprocs.Min(1), maxprocs.Logger(func(string, ...any) {}))

// main CLI application entrypoint.
func main() {
// automatically set GOMAXPROCS to match Linux container CPU quota
_, _ = maxprocs.Set(maxprocs.Min(1), maxprocs.Logger(func(_ string, _ ...any) {}))

if err := run(); err != nil {
_, _ = fmt.Fprintln(os.Stderr, err.Error())

Expand All @@ -27,9 +28,11 @@ func main() {

// run this CLI application.
func run() error {
defer runtime.Gosched() // increase the chance of running deferred functions before exiting

// create a context that is canceled when the user interrupts the program
var ctx, cancel = signal.NotifyContext(context.Background(), syscall.SIGINT, syscall.SIGTERM)
defer cancel()

return (cli.NewApp(filepath.Base(os.Args[0]))).Run(ctx, os.Args)
return cli.NewApp(filepath.Base(os.Args[0])).Run(ctx, os.Args)
}
19 changes: 0 additions & 19 deletions compose.yml

This file was deleted.

2 changes: 1 addition & 1 deletion internal/cli/app.go
Original file line number Diff line number Diff line change
Expand Up @@ -16,7 +16,7 @@ import (
"gh.tarampamp.am/error-pages/internal/logger"
)

//go:generate go run app_generate.go
//go:generate go run update_readme.go

// NewApp creates a new console application.
func NewApp(appName string) *cli.Command {
Expand Down
2 changes: 1 addition & 1 deletion internal/cli/serve/command.go
Original file line number Diff line number Diff line change
Expand Up @@ -220,7 +220,7 @@ func NewCommand(log *logger.Logger) *cli.Command { //nolint:funlen,gocognit,gocy
m[http.CanonicalHeaderKey(strings.TrimSpace(header))] = struct{}{}
}

clear(cfg.ProxyHeaders) // clear the list before adding new headers
cfg.ProxyHeaders = make([]string, 0, len(m)) // clear the list before adding new headers

for header := range m {
cfg.ProxyHeaders = append(cfg.ProxyHeaders, header)
Expand Down
File renamed without changes.