diff --git a/.circleci/config.yml b/.circleci/config.yml index 650ca71..626d8d1 100644 --- a/.circleci/config.yml +++ b/.circleci/config.yml @@ -41,6 +41,10 @@ jobs: - checkout - setup_remote_docker: version: 19.03.13 + - run: + name: Install GPP + command: | + sudo apt-get update && sudo apt-get install -y gpp - run: name: Build Docker image environment: @@ -48,33 +52,8 @@ jobs: PROGRAM: << parameters.program >> BUILD_ID: << pipeline.number >> command: | - if [ "$PROGRAM" = "frontend" ]; then - export IMAGE_NAME="bird-lg-go" - else - export IMAGE_NAME="bird-lgproxy-go" - fi - - export IMAGE_ARCH_GO=$IMAGE_ARCH - if [ "$IMAGE_ARCH" = "i386" ]; then export IMAGE_ARCH_GO="386" ; fi - if [ "$IMAGE_ARCH" = "arm32v7" ]; then export IMAGE_ARCH_GO="arm" ; fi - if [ "$IMAGE_ARCH" = "arm64v8" ]; then export IMAGE_ARCH_GO="arm64"; fi - - docker build \ - --build-arg IMAGE_ARCH=$IMAGE_ARCH_GO \ - -t $DOCKER_USERNAME/$IMAGE_NAME:$IMAGE_ARCH \ - -f $PROGRAM/Dockerfile \ - $PROGRAM - + make _crossbuild echo $DOCKER_PASSWORD | docker login -u $DOCKER_USERNAME --password-stdin - - # Tag image :{arch} and :{arch}-build{build number} - docker push $DOCKER_USERNAME/$IMAGE_NAME:$IMAGE_ARCH - docker tag $DOCKER_USERNAME/$IMAGE_NAME:$IMAGE_ARCH $DOCKER_USERNAME/$IMAGE_NAME:$IMAGE_ARCH-circleci-build$BUILD_ID - docker push $DOCKER_USERNAME/$IMAGE_NAME:$IMAGE_ARCH-circleci-build$BUILD_ID - if [ "$IMAGE_ARCH" = "amd64" ]; then - # Tag as latest for amd64 images - docker tag $DOCKER_USERNAME/$IMAGE_NAME:$IMAGE_ARCH $DOCKER_USERNAME/$IMAGE_NAME:latest - docker push $DOCKER_USERNAME/$IMAGE_NAME:latest - docker tag $DOCKER_USERNAME/$IMAGE_NAME:$IMAGE_ARCH $DOCKER_USERNAME/$IMAGE_NAME:circleci-build$BUILD_ID - docker push $DOCKER_USERNAME/$IMAGE_NAME:latest - fi + make DOCKER_USERNAME=$DOCKER_USERNAME \ + BUILD_ID=circleci-build$BUILD_ID \ + $PROGRAM/$IMAGE_ARCH diff --git a/.gitignore b/.gitignore index 091bd22..9348a77 100644 --- a/.gitignore +++ b/.gitignore @@ -20,3 +20,7 @@ proxy/proxy # don't include generated bindata file frontend/bindata.go + +# don't include generated Dockerfiles +frontend/Dockerfile.* +proxy/Dockerfile.* \ No newline at end of file diff --git a/Makefile b/Makefile new file mode 100644 index 0000000..3903cfa --- /dev/null +++ b/Makefile @@ -0,0 +1,64 @@ +# Basic definitions +DOCKER_USERNAME := xddxdd +ARCHITECTURES := amd64 i386 arm32v7 arm64v8 ppc64le s390x riscv64 x32 +IMAGES := frontend proxy + +# General Purpose Preprocessor config +GPP_INCLUDE_DIR := include +GPP_FLAGS_U := "" "" "(" "," ")" "(" ")" "\#" "" +GPP_FLAGS_M := "\#" "\n" " " " " "\n" "(" ")" +GPP_FLAGS_EXTRA := +c "\\\n" "" +GPP_FLAGS := -I ${GPP_INCLUDE_DIR} --nostdinc -U ${GPP_FLAGS_U} -M ${GPP_FLAGS_M} ${GPP_FLAGS_EXTRA} + +BUILD_ID ?= $(shell date +%Y%m%d%H%M) + +# Function to create targets for image/architecture combos +define create-image-arch-target +$1/Dockerfile.$2: $1/template.Dockerfile + @gpp ${GPP_FLAGS} -D ARCH_$(shell echo $2 | tr a-z A-Z) -o $1/Dockerfile.$2 $1/template.Dockerfile || rm -rf $1/Dockerfile.$2 + +$1/$2: $1/Dockerfile.$2 + @if [ -f $1/Dockerfile.$2 ]; then \ + docker build --pull --no-cache -t ${DOCKER_USERNAME}/$1:$2-${BUILD_ID} -f $1/Dockerfile.$2 $1 || exit 1; \ + docker push ${DOCKER_USERNAME}/$1:$2-${BUILD_ID} || exit 1; \ + docker tag ${DOCKER_USERNAME}/$1:$2-${BUILD_ID} ${DOCKER_USERNAME}/$1:$2 || exit 1; \ + docker push ${DOCKER_USERNAME}/$1:$2 || exit 1; \ + else \ + echo "Dockerfile generation failed, see error above"; \ + exit 1; \ + fi + +endef + +# Function to create targets for images +define create-image-target +$1:$(foreach arch,latest ${ARCHITECTURES},$1/${arch}) + +# Target for latest image, mapping to amd64 +$1/latest: $1/amd64 + @docker tag ${DOCKER_USERNAME}/$1:amd64-${BUILD_ID} ${DOCKER_USERNAME}/$1:${BUILD_ID} || exit 1 + docker push ${DOCKER_USERNAME}/$1:${BUILD_ID} || exit 1 + @docker tag ${DOCKER_USERNAME}/$1:amd64-${BUILD_ID} ${DOCKER_USERNAME}/$1:latest || exit 1 + docker push ${DOCKER_USERNAME}/$1:latest || exit 1 + +$(foreach arch,${ARCHITECTURES},$(eval $(call create-image-arch-target,$1,$(arch)))) +endef + +# By default, build docker images, and do not delete intermediate files +.DEFAULT_GOAL := images +.DELETE_ON_ERROR: +.SECONDARY: + +# Create all targets for image/architecture combos +$(foreach image,${IMAGES},$(eval $(call create-image-target,${image}))) + +# Target to enable multiarch support +_crossbuild: + @docker run --rm --privileged multiarch/qemu-user-static --reset -p yes >/dev/null + +dockerfiles: $(foreach image,${IMAGES},$(foreach arch,${ARCHITECTURES},$(image)/Dockerfile.$(arch))) + +images: $(foreach image,${IMAGES},$(image)) + +clean: + @rm -rf */Dockerfile.{$(shell echo ${ARCHITECTURES} | sed "s/ /,/g")} diff --git a/frontend/Dockerfile b/frontend/Dockerfile deleted file mode 100644 index f86252e..0000000 --- a/frontend/Dockerfile +++ /dev/null @@ -1,19 +0,0 @@ -FROM golang:buster AS step_0 -# -# IMAGE_ARCH is the binary format of the final output -# BUILD_ARCH is the binaary format of the build host -# -ARG IMAGE_ARCH=amd64 -ARG BUILD_ARCH=amd64 -# -ENV CGO_ENABLED=0 GOOS=linux GOARCH=$IMAGE_ARCH GO111MODULE=on -WORKDIR /root -COPY . . -# go-bindata is run on the build host as part of the go generate step -RUN GOARCH=$BUILD_ARCH go get -u github.com/kevinburke/go-bindata/... -RUN go generate -RUN go build -ldflags "-w -s" -o /frontend - -FROM scratch AS step_1 -COPY --from=step_0 /frontend / -ENTRYPOINT ["/frontend"] diff --git a/frontend/template.Dockerfile b/frontend/template.Dockerfile new file mode 100644 index 0000000..0d12377 --- /dev/null +++ b/frontend/template.Dockerfile @@ -0,0 +1,31 @@ +FROM golang:buster AS step_0 + +#if defined(ARCH_AMD64) +ENV GOOS=linux GOARCH=amd64 +#elif defined(ARCH_I386) +ENV GOOS=linux GOARCH=386 +#elif defined(ARCH_ARM32V7) +ENV GOOS=linux GOARCH=arm +#elif defined(ARCH_ARM64V8) +ENV GOOS=linux GOARCH=arm64 +#elif defined(ARCH_PPC64LE) +ENV GOOS=linux GOARCH=ppc64le +#elif defined(ARCH_S390X) +ENV GOOS=linux GOARCH=s390x +#else +#error "Architecture not set" +#endif + +ENV CGO_ENABLED=0 GO111MODULE=on +WORKDIR /root +COPY . . +# go-bindata is run on the build host as part of the go generate step +RUN GOARCH=amd64 go get -u github.com/kevinburke/go-bindata/... +RUN go generate +RUN go build -ldflags "-w -s" -o /frontend + +################################################################################ + +FROM scratch AS step_1 +COPY --from=step_0 /frontend / +ENTRYPOINT ["/frontend"] diff --git a/proxy/Dockerfile b/proxy/Dockerfile deleted file mode 100644 index f5f9646..0000000 --- a/proxy/Dockerfile +++ /dev/null @@ -1,28 +0,0 @@ -FROM golang:buster AS step_0 -# -# IMAGE_ARCH is the binary format of the final output -# -ARG IMAGE_ARCH=amd64 -# -ENV CGO_ENABLED=0 GOOS=linux GOARCH=$IMAGE_ARCH GO111MODULE=on -WORKDIR /root -COPY . . -RUN go build -ldflags "-w -s" -o /proxy - -FROM amd64/debian AS step_1 -ENV TARGET_ARCH=x86_64 -WORKDIR /root -RUN apt-get -qq update && DEBIAN_FRONTEND=noninteractive apt-get -qq install -y \ - build-essential musl-dev musl-tools tar wget git -RUN git clone https://github.com/sabotage-linux/kernel-headers.git -RUN wget https://sourceforge.net/projects/traceroute/files/traceroute/traceroute-2.1.0/traceroute-2.1.0.tar.gz/download \ - -O traceroute-2.1.0.tar.gz -RUN tar xvf traceroute-2.1.0.tar.gz \ - && cd traceroute-2.1.0 \ - && make -j4 CC=musl-gcc CFLAGS="-I/root/kernel-headers/${TARGET_ARCH}/include" LDFLAGS="-static" - -FROM scratch AS step_2 -ENV PATH=/ -COPY --from=step_0 /proxy / -COPY --from=step_1 /root/traceroute-2.1.0/traceroute/traceroute / -ENTRYPOINT ["/proxy"] diff --git a/proxy/template.Dockerfile b/proxy/template.Dockerfile new file mode 100644 index 0000000..0b44bca --- /dev/null +++ b/proxy/template.Dockerfile @@ -0,0 +1,64 @@ +FROM golang:buster AS step_0 + +#if defined(ARCH_AMD64) +ENV GOOS=linux GOARCH=amd64 +#elif defined(ARCH_I386) +ENV GOOS=linux GOARCH=386 +#elif defined(ARCH_ARM32V7) +ENV GOOS=linux GOARCH=arm +#elif defined(ARCH_ARM64V8) +ENV GOOS=linux GOARCH=arm64 +#elif defined(ARCH_PPC64LE) +ENV GOOS=linux GOARCH=ppc64le +#elif defined(ARCH_S390X) +ENV GOOS=linux GOARCH=s390x +#else +#error "Architecture not set" +#endif + +ENV CGO_ENABLED=0 GO111MODULE=on +WORKDIR /root +COPY . . +RUN go build -ldflags "-w -s" -o /proxy + +################################################################################ + +#if defined(ARCH_AMD64) +FROM amd64/debian:sid AS step_1 +ENV TARGET_ARCH=x86_64 +#elif defined(ARCH_I386) +FROM i386/debian:sid AS step_1 +ENV TARGET_ARCH=i386 +#elif defined(ARCH_ARM32V7) +FROM arm32v7/debian:sid AS step_1 +ENV TARGET_ARCH=arm +#elif defined(ARCH_ARM64V8) +FROM arm64v8/debian:sid AS step_1 +ENV TARGET_ARCH=aarch64 +#elif defined(ARCH_PPC64LE) +FROM ppc64le/debian:sid AS step_1 +ENV TARGET_ARCH=ppc64le +#elif defined(ARCH_S390X) +FROM s390x/debian:sid AS step_1 +ENV TARGET_ARCH=s390 +#else +#error "Architecture not set" +#endif + +WORKDIR /root +RUN apt-get -qq update && DEBIAN_FRONTEND=noninteractive apt-get -qq install -y \ + build-essential musl-dev musl-tools tar wget git +RUN git clone https://github.com/sabotage-linux/kernel-headers.git +RUN wget https://sourceforge.net/projects/traceroute/files/traceroute/traceroute-2.1.0/traceroute-2.1.0.tar.gz/download \ + -O traceroute-2.1.0.tar.gz +RUN tar xvf traceroute-2.1.0.tar.gz \ + && cd traceroute-2.1.0 \ + && make -j4 CC=musl-gcc CFLAGS="-I/root/kernel-headers/${TARGET_ARCH}/include" LDFLAGS="-static" + +################################################################################ + +FROM scratch AS step_2 +ENV PATH=/ +COPY --from=step_0 /proxy / +COPY --from=step_1 /root/traceroute-2.1.0/traceroute/traceroute / +ENTRYPOINT ["/proxy"]