diff --git a/.dockerignore b/.dockerignore index 8390d87b6..bcd757988 100644 --- a/.dockerignore +++ b/.dockerignore @@ -1,5 +1,5 @@ dist/ -!dist/traefik +!dist/**/traefik site/ vendor/ .idea/ diff --git a/.github/workflows/experimental.yaml b/.github/workflows/experimental.yaml index 63d7c7bef..a26178315 100644 --- a/.github/workflows/experimental.yaml +++ b/.github/workflows/experimental.yaml @@ -6,6 +6,10 @@ on: - master - v* +env: + GO_VERSION: '1.21' + CGO_ENABLED: 0 + jobs: experimental: @@ -21,17 +25,35 @@ jobs: with: fetch-depth: 0 + - name: Build webui + run: | + make clean-webui generate-webui + + - name: Set up Go ${{ env.GO_VERSION }} + uses: actions/setup-go@v5 + with: + go-version: ${{ env.GO_VERSION }} + + - name: Build + run: make generate binary + - name: Branch name run: echo ${GITHUB_REF##*/} - - name: Build docker experimental image - run: docker build -t traefik/traefik:experimental-${GITHUB_REF##*/} -f exp.Dockerfile . - - name: Login to Docker Hub - uses: docker/login-action@v1 + uses: docker/login-action@v3 with: username: ${{ secrets.DOCKERHUB_USERNAME }} password: ${{ secrets.DOCKERHUB_TOKEN }} - - name: Push to Docker Hub - run: docker push traefik/traefik:experimental-${GITHUB_REF##*/} + - name: Set up QEMU + uses: docker/setup-qemu-action@v2 + + - name: Set up Docker Buildx + uses: docker/setup-buildx-action@v2 + + - name: Build docker experimental image + env: + DOCKER_BUILDX_ARGS: "--push" + run: | + make multi-arch-image-experimental-${GITHUB_REF##*/} diff --git a/.github/workflows/test-integration.yaml b/.github/workflows/test-integration.yaml index bcbc3ec21..d5c4e5ca1 100644 --- a/.github/workflows/test-integration.yaml +++ b/.github/workflows/test-integration.yaml @@ -71,4 +71,5 @@ jobs: - name: Run Integration tests run: | - go test ./integration -test.timeout=20m -failfast -v -run "${{ steps.test_split.outputs.run}}" + TESTS=$(echo "${{ steps.test_split.outputs.run}}" | sed 's/\$/\$\$/g') + TESTFLAGS="-run \"${TESTS}\"" make test-integration diff --git a/.github/workflows/validate.yaml b/.github/workflows/validate.yaml index 1c0822abe..f836e94ee 100644 --- a/.github/workflows/validate.yaml +++ b/.github/workflows/validate.yaml @@ -54,7 +54,7 @@ jobs: - name: go generate run: | - go generate + make generate git diff --exit-code - name: go mod tidy diff --git a/Dockerfile b/Dockerfile index 873d55312..fea809225 100644 --- a/Dockerfile +++ b/Dockerfile @@ -1,6 +1,13 @@ -FROM scratch -COPY script/ca-certificates.crt /etc/ssl/certs/ -COPY dist/traefik / +# syntax=docker/dockerfile:1.2 +FROM alpine:3.19 + +RUN apk --no-cache --no-progress add ca-certificates tzdata \ + && rm -rf /var/cache/apk/* + +ARG TARGETPLATFORM +COPY ./dist/$TARGETPLATFORM/traefik / + EXPOSE 80 VOLUME ["/tmp"] + ENTRYPOINT ["/traefik"] diff --git a/Makefile b/Makefile index 668c5404e..1a8f40b37 100644 --- a/Makefile +++ b/Makefile @@ -7,8 +7,22 @@ VERSION := $(if $(VERSION),$(VERSION),$(VERSION_GIT)) GIT_BRANCH := $(subst heads/,,$(shell git rev-parse --abbrev-ref HEAD 2>/dev/null)) +REPONAME := $(shell echo $(REPO) | tr '[:upper:]' '[:lower:]') +BIN_NAME := traefik +CODENAME := cheddar + +DATE := $(shell date -u '+%Y-%m-%d_%I:%M:%S%p') + +# Default build target +GOOS := $(shell go env GOOS) +GOARCH := $(shell go env GOARCH) + +LINT_EXECUTABLES = misspell shellcheck + +DOCKER_BUILD_PLATFORMS ?= linux/amd64,linux/arm64 + .PHONY: default -default: binary +default: generate binary ## Create the "dist" directory dist: @@ -35,43 +49,57 @@ webui/static/index.html: .PHONY: generate-webui generate-webui: webui/static/index.html +## Generate code +.PHONY: generate +generate: + go generate + ## Build the binary .PHONY: binary -binary: generate-webui - ./script/make.sh generate binary +binary: generate-webui dist + @echo SHA: $(VERSION) $(CODENAME) $(DATE) + CGO_ENABLED=0 GOGC=off GOOS=${GOOS} GOARCH=${GOARCH} go build ${FLAGS[*]} -ldflags "-s -w \ + -X github.com/traefik/traefik/v2/pkg/version.Version=$(VERSION) \ + -X github.com/traefik/traefik/v2/pkg/version.Codename=$(CODENAME) \ + -X github.com/traefik/traefik/v2/pkg/version.BuildDate=$(DATE)" \ + -installsuffix nocgo -o "./dist/${GOOS}/${GOARCH}/$(BIN_NAME)" ./cmd/traefik -## Build the linux binary locally -.PHONY: binary-debug -binary-debug: generate-webui - GOOS=linux ./script/make.sh binary +binary-linux-arm64: export GOOS := linux +binary-linux-arm64: export GOARCH := arm64 +binary-linux-arm64: + @$(MAKE) binary + +binary-linux-amd64: export GOOS := linux +binary-linux-amd64: export GOARCH := amd64 +binary-linux-amd64: + @$(MAKE) binary + +binary-windows-amd64: export GOOS := windows +binary-windows-amd64: export GOARCH := amd64 +binary-windows-amd64: export BIN_NAME := traefik.exe +binary-windows-amd64: + @$(MAKE) binary ## Build the binary for the standard platforms (linux, darwin, windows) .PHONY: crossbinary-default -crossbinary-default: generate-webui - ./script/make.sh generate crossbinary-default - -## Build the binary for the standard platforms (linux, darwin, windows) in parallel -.PHONY: crossbinary-default-parallel -crossbinary-default-parallel: - $(MAKE) generate-webui - $(MAKE) crossbinary-default +crossbinary-default: generate generate-webui + $(CURDIR)/script/crossbinary-default.sh ## Run the unit and integration tests .PHONY: test -test: - ./script/make.sh generate test-unit binary test-integration +test: test-unit test-integration ## Run the unit tests .PHONY: test-unit test-unit: - ./script/make.sh generate test-unit + GOOS=$(GOOS) GOARCH=$(GOARCH) go test -cover "-coverprofile=cover.out" -v $(TESTFLAGS) ./pkg/... ./cmd/... ## Run the integration tests .PHONY: test-integration -test-integration: - ./script/make.sh generate binary test-integration +test-integration: binary + GOOS=$(GOOS) GOARCH=$(GOARCH) go test ./integration -test.timeout=20m -failfast -v $(TESTFLAGS) -## Pull all images for integration tests +## Pull all Docker images to avoid timeout during integration tests .PHONY: pull-images pull-images: grep --no-filename -E '^\s+image:' ./integration/resources/compose/*.yml \ @@ -80,38 +108,47 @@ pull-images: | uniq \ | xargs -P 6 -n 1 docker pull -EXECUTABLES = misspell shellcheck +## Lint run golangci-lint +.PHONY: lint +lint: + golangci-lint run ## Validate code and docs .PHONY: validate-files -validate-files: - $(foreach exec,$(EXECUTABLES),\ +validate-files: lint + $(foreach exec,$(LINT_EXECUTABLES),\ $(if $(shell which $(exec)),,$(error "No $(exec) in PATH"))) - ./script/make.sh generate validate-lint validate-misspell - bash $(CURDIR)/script/validate-shell-script.sh + $(CURDIR)/script/validate-misspell.sh + $(CURDIR)/script/validate-shell-script.sh ## Validate code, docs, and vendor .PHONY: validate -validate: +validate: lint $(foreach exec,$(EXECUTABLES),\ $(if $(shell which $(exec)),,$(error "No $(exec) in PATH"))) - ./script/make.sh generate validate-lint validate-misspell validate-vendor - bash $(CURDIR)/script/validate-shell-script.sh + $(CURDIR)/script/validate-vendor.sh + $(CURDIR)/script/validate-misspell.sh + $(CURDIR)/script/validate-shell-script.sh + +# Target for building images for multiple architectures. +.PHONY: multi-arch-image-% +multi-arch-image-%: binary-linux-amd64 binary-linux-arm64 + docker buildx build $(DOCKER_BUILDX_ARGS) -t traefik/traefik:$* --platform=$(DOCKER_BUILD_PLATFORMS) -f Dockerfile . + ## Clean up static directory and build a Docker Traefik image .PHONY: build-image -build-image: clean-webui binary - docker build -t $(TRAEFIK_IMAGE) . +build-image: export DOCKER_BUILDX_ARGS := --load +build-image: export DOCKER_BUILD_PLATFORMS := linux/$(GOARCH) +build-image: clean-webui + @$(MAKE) multi-arch-image-latest -## Build a Docker Traefik image without re-building the webui +## Build a Docker Traefik image without re-building the webui when it's already built .PHONY: build-image-dirty -build-image-dirty: binary - docker build -t $(TRAEFIK_IMAGE) . - -## Locally build traefik for linux, then shove it an alpine image, with basic tools. -.PHONY: build-image-debug -build-image-debug: binary-debug - docker build -t $(TRAEFIK_IMAGE) -f debug.Dockerfile . +build-image-dirty: export DOCKER_BUILDX_ARGS := --load +build-image-dirty: export DOCKER_BUILD_PLATFORMS := linux/$(GOARCH) +build-image-dirty: + @$(MAKE) multi-arch-image-latest ## Build documentation site .PHONY: docs @@ -141,30 +178,9 @@ generate-genconf: ## Create packages for the release .PHONY: release-packages release-packages: generate-webui - rm -rf dist - @- $(foreach os, linux darwin windows freebsd openbsd, \ - goreleaser release --skip-publish -p 2 --timeout="90m" --config $(shell go run ./internal/release $(os)); \ - go clean -cache; \ - ) - - cat dist/**/*_checksums.txt >> dist/traefik_${VERSION}_checksums.txt - rm dist/**/*_checksums.txt - tar cfz dist/traefik-${VERSION}.src.tar.gz \ - --exclude-vcs \ - --exclude .idea \ - --exclude .travis \ - --exclude .semaphoreci \ - --exclude .github \ - --exclude dist . - chown -R $(shell id -u):$(shell id -g) dist/ + $(CURDIR)/script/release-packages.sh ## Format the Code .PHONY: fmt fmt: gofmt -s -l -w $(SRCS) - -.PHONY: run-dev -run-dev: - go generate - GO111MODULE=on go build ./cmd/traefik - ./traefik diff --git a/build.Dockerfile b/build.Dockerfile deleted file mode 100644 index 587424c38..000000000 --- a/build.Dockerfile +++ /dev/null @@ -1,37 +0,0 @@ -FROM golang:1.21-alpine - -RUN apk --no-cache --no-progress add git mercurial bash gcc musl-dev curl tar ca-certificates tzdata \ - && update-ca-certificates \ - && rm -rf /var/cache/apk/* - -# Which docker version to test on -ARG DOCKER_VERSION=18.09.7 - -# Download docker -RUN mkdir -p /usr/local/bin \ - && curl -fL https://download.docker.com/linux/static/stable/x86_64/docker-${DOCKER_VERSION}.tgz \ - | tar -xzC /usr/local/bin --transform 's#^.+/##x' - -# Download golangci-lint binary to bin folder in $GOPATH -RUN curl -sfL https://raw.githubusercontent.com/golangci/golangci-lint/master/install.sh | bash -s -- -b $GOPATH/bin v1.55.2 - -# Download misspell binary to bin folder in $GOPATH -RUN curl -sfL https://raw.githubusercontent.com/golangci/misspell/master/install-misspell.sh | bash -s -- -b $GOPATH/bin v0.4.0 - -# Download goreleaser binary to bin folder in $GOPATH -RUN curl -sfL https://gist.githubusercontent.com/traefiker/6d7ac019c11d011e4f131bb2cca8900e/raw/goreleaser.sh | sh - -WORKDIR /go/src/github.com/traefik/traefik - -# Because of CVE-2022-24765 (https://github.blog/2022-04-12-git-security-vulnerability-announced/), -# we configure git to allow the Traefik codebase path on the Host for docker in docker usages. -ARG HOST_PWD="" - -RUN git config --global --add safe.directory "${HOST_PWD}" - -# Download go modules -COPY go.mod . -COPY go.sum . -RUN GO111MODULE=on GOPROXY=https://proxy.golang.org go mod download - -COPY . /go/src/github.com/traefik/traefik diff --git a/debug.Dockerfile b/debug.Dockerfile deleted file mode 100644 index 4dcf88bf8..000000000 --- a/debug.Dockerfile +++ /dev/null @@ -1,10 +0,0 @@ -FROM alpine:3.14 -# Feel free to add below any helpful dependency for debugging. -# iproute2 is for ss. -RUN apk --no-cache --no-progress add bash curl ca-certificates tzdata lsof iproute2 \ - && update-ca-certificates \ - && rm -rf /var/cache/apk/* -COPY dist/traefik / -EXPOSE 80 -VOLUME ["/tmp"] -ENTRYPOINT ["/traefik"] diff --git a/docs/content/contributing/building-testing.md b/docs/content/contributing/building-testing.md index 838688869..20d05740a 100644 --- a/docs/content/contributing/building-testing.md +++ b/docs/content/contributing/building-testing.md @@ -58,10 +58,12 @@ Once you've set up your go environment and cloned the source repository, you can ```bash $ make binary -./script/make.sh generate binary ----> Making bundle: generate (in .) - ----> Making bundle: binary (in .) +SHA: 8fddfe118288bb5280eb5e77fa952f52def360b4 cheddar 2024-01-11_03:14:57PM +CGO_ENABLED=0 GOGC=off GOOS=darwin GOARCH=arm64 go build -ldflags "-s -w \ + -X github.com/traefik/traefik/v2/pkg/version.Version=8fddfe118288bb5280eb5e77fa952f52def360b4 \ + -X github.com/traefik/traefik/v2/pkg/version.Codename=cheddar \ + -X github.com/traefik/traefik/v2/pkg/version.BuildDate=2024-01-11_03:14:57PM" \ + -installsuffix nocgo -o "./dist/darwin/arm64/traefik" ./cmd/traefik $ ls dist/ traefik* @@ -77,10 +79,7 @@ Run all tests (unit and integration) using the `test` target. ```bash $ make test-unit -./script/make.sh generate test-unit ----> Making bundle: generate (in .) - ----> Making bundle: test-unit (in .) +GOOS=darwin GOARCH=arm64 go test -cover "-coverprofile=cover.out" -v ./pkg/... ./cmd/... + go test -cover -coverprofile=cover.out . ok github.com/traefik/traefik 0.005s coverage: 4.1% of statements diff --git a/exp.Dockerfile b/exp.Dockerfile deleted file mode 100644 index 8098f9218..000000000 --- a/exp.Dockerfile +++ /dev/null @@ -1,47 +0,0 @@ -# WEBUI -FROM node:12.11 as webui - -ENV WEBUI_DIR /src/webui -RUN mkdir -p $WEBUI_DIR - -COPY ./webui/ $WEBUI_DIR/ - -WORKDIR $WEBUI_DIR - -RUN yarn install -RUN yarn build - -# BUILD -FROM golang:1.21-alpine as gobuild - -RUN apk --no-cache --no-progress add git mercurial bash gcc musl-dev curl tar ca-certificates tzdata \ - && update-ca-certificates \ - && rm -rf /var/cache/apk/* - -WORKDIR /go/src/github.com/traefik/traefik - -# Download go modules -COPY go.mod . -COPY go.sum . -RUN GO111MODULE=on GOPROXY=https://proxy.golang.org go mod download - -COPY . /go/src/github.com/traefik/traefik - -RUN rm -rf /go/src/github.com/traefik/traefik/webui/static/ -COPY --from=webui /src/webui/static/ /go/src/github.com/traefik/traefik/webui/static/ - -RUN ./script/make.sh generate binary - -## IMAGE -FROM alpine:3.14 - -RUN apk --no-cache --no-progress add bash curl ca-certificates tzdata \ - && update-ca-certificates \ - && rm -rf /var/cache/apk/* - -COPY --from=gobuild /go/src/github.com/traefik/traefik/dist/traefik / - -EXPOSE 80 -VOLUME ["/tmp"] - -ENTRYPOINT ["/traefik"] diff --git a/integration/integration_test.go b/integration/integration_test.go index 9dc04dc38..0ded401de 100644 --- a/integration/integration_test.go +++ b/integration/integration_test.go @@ -15,6 +15,7 @@ import ( "os/exec" "path/filepath" "regexp" + "runtime" "slices" "strings" "testing" @@ -56,8 +57,6 @@ type composeDeploy struct { Replicas int `yaml:"replicas"` } -var traefikBinary = "../dist/traefik" - type BaseSuite struct { suite.Suite containers map[string]testcontainers.Container @@ -308,7 +307,13 @@ func (s *BaseSuite) composeDown() { } func (s *BaseSuite) cmdTraefik(args ...string) (*exec.Cmd, *bytes.Buffer) { - cmd := exec.Command(traefikBinary, args...) + binName := "traefik" + if runtime.GOOS == "windows" { + binName += ".exe" + } + + traefikBinPath := filepath.Join("..", "dist", runtime.GOOS, runtime.GOARCH, binName) + cmd := exec.Command(traefikBinPath, args...) s.T().Cleanup(func() { s.killCmd(cmd) diff --git a/script/binary b/script/binary deleted file mode 100755 index 3a3e94b61..000000000 --- a/script/binary +++ /dev/null @@ -1,30 +0,0 @@ -#!/usr/bin/env bash -set -e - -rm -f dist/traefik - -FLAGS=() -if [ -n "${VERBOSE}" ]; then - FLAGS+=(-v) -fi - -if [ -z "${VERSION}" ]; then - VERSION=$(git rev-parse HEAD) -fi - -if [ -z "$CODENAME" ]; then - CODENAME=cheddar -fi - -if [ -z "$DATE" ]; then - DATE=$(date -u '+%Y-%m-%d_%I:%M:%S%p') -fi - -# Build binaries -# shellcheck disable=SC2086 -# shellcheck disable=SC2048 -CGO_ENABLED=0 GOGC=off go build ${FLAGS[*]} -ldflags "-s -w \ - -X github.com/traefik/traefik/v2/pkg/version.Version=$VERSION \ - -X github.com/traefik/traefik/v2/pkg/version.Codename=$CODENAME \ - -X github.com/traefik/traefik/v2/pkg/version.BuildDate=$DATE" \ - -installsuffix nocgo -o dist/traefik ./cmd/traefik diff --git a/script/crossbinary-default b/script/crossbinary-default.sh similarity index 100% rename from script/crossbinary-default rename to script/crossbinary-default.sh diff --git a/script/generate b/script/generate deleted file mode 100755 index 423970b5a..000000000 --- a/script/generate +++ /dev/null @@ -1,4 +0,0 @@ -#!/usr/bin/env bash -set -e - -go generate diff --git a/script/make.sh b/script/make.sh deleted file mode 100755 index 2f3870e74..000000000 --- a/script/make.sh +++ /dev/null @@ -1,35 +0,0 @@ -#!/usr/bin/env bash -set -e - -export GO111MODULE=on -export GOPROXY=https://proxy.golang.org - -# List of bundles to create when no argument is passed -DEFAULT_BUNDLES=( - generate - validate-lint - binary - - test-unit - test-integration -) - -SCRIPT_DIR="$(cd "$(dirname "${0}")" && pwd -P)" - -bundle() { - local bundle="$1"; shift - echo "---> Making bundle: $(basename "${bundle}") (in $SCRIPT_DIR)" - # shellcheck source=/dev/null - source "${SCRIPT_DIR}/${bundle}" -} - -if [ $# -lt 1 ]; then - bundles=${DEFAULT_BUNDLES[*]} -else - bundles=${*} -fi -# shellcheck disable=SC2048 -for bundle in ${bundles[*]}; do - bundle "${bundle}" - echo -done diff --git a/script/release-packages.sh b/script/release-packages.sh new file mode 100755 index 000000000..f442e12dd --- /dev/null +++ b/script/release-packages.sh @@ -0,0 +1,28 @@ +#!/usr/bin/env bash +set -e + +if [ -n "${SEMAPHORE_GIT_TAG_NAME}" ]; then + echo "Releasing packages..." +else + echo "Skipping release" + exit 0 +fi + +rm -rf dist + +for os in linux darwin windows freebsd openbsd; do + goreleaser release --snapshot --skip=publish -p 2 --timeout="90m" --config "$(go run ./internal/release "$os")" + go clean -cache +done + +cat dist/**/*_checksums.txt >> dist/traefik_${VERSION}_checksums.txt +rm dist/**/*_checksums.txt +tar cfz dist/traefik-${VERSION}.src.tar.gz \ + --exclude-vcs \ + --exclude .idea \ + --exclude .travis \ + --exclude .semaphoreci \ + --exclude .github \ + --exclude dist . + +chown -R $(id -u):$(id -g) dist/ diff --git a/script/test-integration b/script/test-integration deleted file mode 100755 index a6afba7d1..000000000 --- a/script/test-integration +++ /dev/null @@ -1,11 +0,0 @@ -#!/usr/bin/env bash -set -e - -export DEST=. - -echo "Testing against..." -docker version - -# shellcheck disable=SC2086 -# shellcheck disable=SC2048 -go test ./integration -test.timeout=20m -failfast -v ${TESTFLAGS[*]} diff --git a/script/test-unit b/script/test-unit deleted file mode 100755 index 8f5ef0189..000000000 --- a/script/test-unit +++ /dev/null @@ -1,29 +0,0 @@ -#!/usr/bin/env bash -set -e - -RED=$'\033[31m' -GREEN=$'\033[32m' -TEXTRESET=$'\033[0m' # reset the foreground colour - -# -failfast -timeout=5m -TESTFLAGS=(-cover "-coverprofile=cover.out" "${TESTFLAGS}") - -if [ -n "${VERBOSE}" ]; then - TESTFLAGS+=(-v) -elif [ -n "${VERBOSE_UNIT}" ]; then - TESTFLAGS+=(-v) -fi - -set +e - -# shellcheck disable=SC2086 -# shellcheck disable=SC2048 -go test ${TESTFLAGS[*]} ./pkg/... - -CODE=$? -if [ ${CODE} != 0 ]; then - echo "${RED}Tests failed [code ${CODE}].${TEXTRESET}" - exit ${CODE} -else - echo "${GREEN}Tests succeed.${TEXTRESET}" -fi diff --git a/script/validate-lint b/script/validate-lint deleted file mode 100755 index 937f7f13b..000000000 --- a/script/validate-lint +++ /dev/null @@ -1,3 +0,0 @@ -#!/usr/bin/env bash - -golangci-lint run diff --git a/script/validate-misspell b/script/validate-misspell.sh similarity index 100% rename from script/validate-misspell rename to script/validate-misspell.sh diff --git a/script/validate-vendor b/script/validate-vendor.sh similarity index 100% rename from script/validate-vendor rename to script/validate-vendor.sh