Skip to content

Commit

Permalink
Support cross-compiling for clients
Browse files Browse the repository at this point in the history
Signed-off-by: Andy Goldstein <andy.goldstein@gmail.com>
  • Loading branch information
ncdc committed Oct 24, 2017
1 parent a1b43c4 commit e38b6d0
Show file tree
Hide file tree
Showing 18 changed files with 382 additions and 92 deletions.
4 changes: 4 additions & 0 deletions .gitignore
Original file line number Diff line number Diff line change
Expand Up @@ -28,3 +28,7 @@ debug

/ark
.idea/

.container-*
.vimrc
.go
16 changes: 8 additions & 8 deletions Dockerfile → Dockerfile.in
Original file line number Diff line number Diff line change
@@ -1,4 +1,6 @@
# Copyright 2017 Heptio Inc.
# Copyright 2016 The Kubernetes Authors.
#
# Modifications Copyright 2017 the Heptio Ark contributors.
#
# Licensed under the Apache License, Version 2.0 (the "License");
# you may not use this file except in compliance with the License.
Expand All @@ -12,13 +14,11 @@
# See the License for the specific language governing permissions and
# limitations under the License.

FROM alpine:3.6
MAINTAINER Andy Goldstein "andy@heptio.com"
FROM ARG_FROM

RUN apk add --no-cache ca-certificates && \
adduser -S -D -H -u 1000 ark
MAINTAINER Andy Goldstein <andy@heptio.com>

ADD _output/bin/ark /ark
ADD /bin/ARG_OS/ARG_ARCH/ARG_BIN /ARG_BIN

USER ark
ENTRYPOINT ["/ark"]
USER nobody:nobody
ENTRYPOINT ["/ARG_BIN"]
213 changes: 135 additions & 78 deletions Makefile
Original file line number Diff line number Diff line change
@@ -1,4 +1,6 @@
# Copyright 2017 Heptio Inc.
# Copyright 2016 The Kubernetes Authors.
#
# Modifications Copyright 2017 the Heptio Ark contributors.
#
# Licensed under the Apache License, Version 2.0 (the "License");
# you may not use this file except in compliance with the License.
Expand All @@ -12,99 +14,154 @@
# See the License for the specific language governing permissions and
# limitations under the License.

# project related vars
ROOT_DIR := $(shell dirname $(abspath $(lastword $(MAKEFILE_LIST))))
PROJECT = ark
VERSION ?= v0.4.0
GOTARGET = github.com/heptio/$(PROJECT)
OUTPUT_DIR = $(ROOT_DIR)/_output
BIN_DIR = $(OUTPUT_DIR)/bin
GIT_SHA=$(shell git rev-parse --short HEAD)
GIT_DIRTY=$(shell git status --porcelain $(ROOT_DIR) 2> /dev/null)
ifeq ($(GIT_DIRTY),)
GIT_TREE_STATE := clean
else
GIT_TREE_STATE := dirty
endif
# The binary to build (just the basename).
BIN := ark

# This repo's root import path (under GOPATH).
PKG := github.com/heptio/ark

# docker related vars
# Where to push the docker image.
REGISTRY ?= gcr.io/heptio-images
BUILD_IMAGE ?= gcr.io/heptio-images/golang:1.8-alpine3.6
LDFLAGS = -X $(GOTARGET)/pkg/buildinfo.Version=$(VERSION)
LDFLAGS += -X $(GOTARGET)/pkg/buildinfo.DockerImage=$(REGISTRY)/$(PROJECT)
LDFLAGS += -X $(GOTARGET)/pkg/buildinfo.GitSHA=$(GIT_SHA)
LDFLAGS += -X $(GOTARGET)/pkg/buildinfo.GitTreeState=$(GIT_TREE_STATE)
# go build -i installs compiled packages so they can be reused later.
# This speeds up recompiles.
BUILDCMD = go build -i -v -ldflags "$(LDFLAGS)"
BUILDMNT = /go/src/$(GOTARGET)
EXTRA_MNTS ?=

# test related vars
TESTARGS ?= -timeout 60s
TEST_PKGS ?= ./cmd/... ./pkg/...
SKIP_TESTS ?=

# what we're building
BINARIES = ark
# Which architecture to build - see $(ALL_ARCH) for options.
ARCH ?= linux-amd64

local: $(BINARIES)
VERSION ?= master

$(BINARIES):
mkdir -p $(BIN_DIR)
$(BUILDCMD) -o $(BIN_DIR)/$@ $(GOTARGET)/cmd/$@
###
### These variables should not need tweaking.
###

fmt:
gofmt -w=true $$(find . -type f -name '*.go' -not -path "./vendor/*" -not -path "./pkg/generated/*")
goimports -w=true -d $$(find . -type f -name '*.go' -not -path "./vendor/*" -not -path "./pkg/generated/*")
SRC_DIRS := cmd pkg # directories which hold app source (not vendored)

CLI_PLATFORMS := linux-amd64 linux-arm linux-arm64 darwin-amd64 windows-amd64
CONTAINER_PLATFORMS := linux-amd64 linux-arm linux-arm64

platform_temp = $(subst -, ,$(ARCH))
GOOS = $(word 1, $(platform_temp))
GOARCH = $(word 2, $(platform_temp))

BASEIMAGE?=alpine:3.6

# TODO(ncdc): support multiple image architectures once gcr.io supports manifest lists
# Set default base image dynamically for each arch
#ifeq ($(GOARCH),amd64)
# BASEIMAGE?=alpine:3.6
#endif
#ifeq ($(GOARCH),arm)
# BASEIMAGE?=armel/busybox
#endif
#ifeq ($(GOARCH),arm64)
# BASEIMAGE?=aarch64/busybox
#endif

IMAGE := $(REGISTRY)/$(BIN)

BUILD_IMAGE ?= gcr.io/heptio-images/golang:1.9-alpine3.6

# If you want to build all binaries, see the 'all-build' rule.
# If you want to build all containers, see the 'all-container' rule.
# If you want to build AND push all containers, see the 'all-push' rule.
all: build

build-%:
@$(MAKE) --no-print-directory ARCH=$* build

#container-%:
# @$(MAKE) --no-print-directory ARCH=$* container

#push-%:
# @$(MAKE) --no-print-directory ARCH=$* push

test:
all-build: $(addprefix build-, $(CLI_PLATFORMS))

#all-container: $(addprefix container-, $(CONTAINER_PLATFORMS))

#all-push: $(addprefix push-, $(CONTAINER_PLATFORMS))

build: _output/bin/$(GOOS)/$(GOARCH)/$(BIN)

_output/bin/$(GOOS)/$(GOARCH)/$(BIN): build-dirs
@echo "building: $@"
@$(MAKE) shell CMD="-c '\
GOOS=$(GOOS) \
GOARCH=$(GOARCH) \
VERSION=$(VERSION) \
PKG=$(PKG) \
BIN=$(BIN) \
./hack/build.sh'"

TTY := $(shell tty -s && echo "-t")

# Example: make shell CMD="date > datefile"
shell: build-dirs
@docker run \
-i $(TTY) \
--rm \
-u $$(id -u):$$(id -g) \
-v "$$(pwd)/.go/pkg:/go/pkg" \
-v "$$(pwd)/.go/src:/go/src" \
-v "$$(pwd)/.go/std:/go/std" \
-v "$$(pwd):/go/src/$(PKG)" \
-v "$$(pwd)/_output/bin:/output" \
-v "$$(pwd)/.go/std/$(GOOS)/$(GOARCH):/usr/local/go/pkg/$(GOOS)_$(GOARCH)_static" \
-w /go/src/$(PKG) \
$(BUILD_IMAGE) \
/bin/sh $(CMD)

DOTFILE_IMAGE = $(subst :,_,$(subst /,_,$(IMAGE))-$(VERSION))

container: verify test .container-$(DOTFILE_IMAGE) container-name
.container-$(DOTFILE_IMAGE): _output/bin/$(GOOS)/$(GOARCH)/$(BIN) Dockerfile.in
@sed \
-e 's|ARG_BIN|$(BIN)|g' \
-e 's|ARG_OS|$(GOOS)|g' \
-e 's|ARG_ARCH|$(GOARCH)|g' \
-e 's|ARG_FROM|$(BASEIMAGE)|g' \
Dockerfile.in > _output/.dockerfile-$(GOOS)-$(GOARCH)
@docker build -t $(IMAGE):$(VERSION) -f _output/.dockerfile-$(GOOS)-$(GOARCH) _output
@docker images -q $(IMAGE):$(VERSION) > $@

container-name:
@echo "container: $(IMAGE):$(VERSION)"

push: .push-$(DOTFILE_IMAGE) push-name
.push-$(DOTFILE_IMAGE): .container-$(DOTFILE_IMAGE)
ifeq ($(findstring gcr.io,$(REGISTRY)),gcr.io)
@gcloud docker -- push $(IMAGE):$(VERSION)
else
@docker push $(IMAGE):$(VERSION)
endif
@docker images -q $(IMAGE):$(VERSION) > $@

push-name:
@echo "pushed: $(IMAGE):$(VERSION)"

SKIP_TESTS ?=
test: build-dirs
ifneq ($(SKIP_TESTS), 1)
# go test -i installs compiled packages so they can be reused later
# This speeds up retests.
go test -i -v $(TEST_PKGS)
go test $(TEST_PKGS) $(TESTARGS)
@$(MAKE) shell CMD="-c 'hack/test.sh $(SRC_DIRS)'"
endif

fmt:
@$(MAKE) shell CMD="-c 'hack/update-fmt.sh'"

verify:
ifneq ($(SKIP_TESTS), 1)
${ROOT_DIR}/hack/verify-generated-docs.sh
${ROOT_DIR}/hack/verify-generated-clientsets.sh
${ROOT_DIR}/hack/verify-generated-listers.sh
${ROOT_DIR}/hack/verify-generated-informers.sh
@$(MAKE) shell CMD="-c 'hack/verify-all.sh'"
endif

update: fmt
${ROOT_DIR}/hack/update-generated-clientsets.sh
${ROOT_DIR}/hack/update-generated-listers.sh
${ROOT_DIR}/hack/update-generated-informers.sh
${ROOT_DIR}/hack/update-generated-docs.sh

all: cbuild container

cbuild:
@docker run --rm \
-v $(ROOT_DIR):$(BUILDMNT) \
$(EXTRA_MNTS) \
-w $(BUILDMNT) \
-e SKIP_TESTS=$(SKIP_TESTS) \
$(BUILD_IMAGE) \
/bin/sh -c " \
VERSION=$(VERSION) \
make local verify test \
"

container: cbuild
@docker build -t $(REGISTRY)/$(PROJECT):latest -t $(REGISTRY)/$(PROJECT):$(VERSION) .
@$(MAKE) shell CMD="-c 'hack/update-all.sh'"

container-local: $(BINARIES)
@docker build -t $(REGISTRY)/$(PROJECT):latest -t $(REGISTRY)/$(PROJECT):$(VERSION) .
build-dirs:
@mkdir -p _output/bin/$(GOOS)/$(GOARCH)
@mkdir -p .go/src/$(PKG) .go/pkg .go/bin .go/std/$(GOOS)/$(GOARCH)

push:
docker -- push $(REGISTRY)/$(PROJECT):$(VERSION)
clean: container-clean bin-clean

.PHONY: all local container cbuild push test verify update fmt $(BINARIES)
container-clean:
rm -rf .container-* _output/.dockerfile-* .push-*

clean:
rm -rf $(OUTPUT_DIR)
@docker rmi $(REGISTRY)/$(PROJECT):latest $(REGISTRY)/$(PROJECT):$(VERSION) 2>/dev/null || :
bin-clean:
rm -rf .go _output
65 changes: 65 additions & 0 deletions hack/build.sh
Original file line number Diff line number Diff line change
@@ -0,0 +1,65 @@
#!/bin/sh

# Copyright 2016 The Kubernetes Authors.
#
# Licensed under the Apache License, Version 2.0 (the "License");
# you may not use this file except in compliance with the License.
# You may obtain a copy of the License at
#
# http://www.apache.org/licenses/LICENSE-2.0
#
# Unless required by applicable law or agreed to in writing, software
# distributed under the License is distributed on an "AS IS" BASIS,
# WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
# See the License for the specific language governing permissions and
# limitations under the License.

set -o errexit
set -o nounset
set -o pipefail

if [ -z "${PKG}" ]; then
echo "PKG must be set"
exit 1
fi
if [ -z "${BIN}" ]; then
echo "BIN must be set"
exit 1
fi
if [ -z "${GOOS}" ]; then
echo "GOOS must be set"
exit 1
fi
if [ -z "${GOARCH}" ]; then
echo "GOARCH must be set"
exit 1
fi
if [ -z "${VERSION}" ]; then
echo "VERSION must be set"
exit 1
fi

export CGO_ENABLED=0

GIT_SHA=$(git describe --tags --always)
GIT_DIRTY=$(git status --porcelain 2> /dev/null)
if [[ -z "${GIT_DIRTY}" ]]; then
GIT_TREE_STATE=clean
else
GIT_TREE_STATE=dirty
fi

LDFLAGS="-X ${PKG}/pkg/buildinfo.Version=${VERSION}"
LDFLAGS="${LDFLAGS} -X ${PKG}/pkg/buildinfo.GitSHA=${GIT_SHA}"
LDFLAGS="${LDFLAGS} -X ${PKG}/pkg/buildinfo.GitTreeState=${GIT_TREE_STATE}"

OUTPUT=/output/${GOOS}/${GOARCH}/${BIN}
if [[ "${GOOS}" = "windows" ]]; then
OUTPUT="${OUTPUT}.exe"
fi

go build -i \
-o ${OUTPUT} \
-installsuffix "static" \
-ldflags "${LDFLAGS}" \
${PKG}/cmd/${BIN}
55 changes: 55 additions & 0 deletions hack/test.sh
Original file line number Diff line number Diff line change
@@ -0,0 +1,55 @@
#!/bin/sh

# Copyright 2016 The Kubernetes Authors.
#
# Licensed under the Apache License, Version 2.0 (the "License");
# you may not use this file except in compliance with the License.
# You may obtain a copy of the License at
#
# http://www.apache.org/licenses/LICENSE-2.0
#
# Unless required by applicable law or agreed to in writing, software
# distributed under the License is distributed on an "AS IS" BASIS,
# WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
# See the License for the specific language governing permissions and
# limitations under the License.

set -o errexit
set -o nounset
set -o pipefail

export CGO_ENABLED=0

TARGETS=$(for d in "$@"; do echo ./$d/...; done)

echo "Running tests:"
go test -i -installsuffix "static" ${TARGETS}
go test -installsuffix "static" -timeout 60s ${TARGETS}
echo

echo -n "Checking gofmt: "
ERRS=$(find "$@" -type f -name \*.go | xargs gofmt -l 2>&1 || true)
if [ -n "${ERRS}" ]; then
echo "FAIL - the following files need to be gofmt'ed:"
for e in ${ERRS}; do
echo " $e"
done
echo
exit 1
fi
echo "PASS"
echo

# TODO(ncdc): there are govet failures in the generated clientset and the log error location hook
# that prevent us from running vet at this time.
#
# echo -n "Checking go vet: "
# ERRS=$(go vet ${TARGETS} 2>&1 || true)
# if [ -n "${ERRS}" ]; then
# echo "FAIL"
# echo "${ERRS}"
# echo
# exit 1
# fi
# echo "PASS"
# echo
Loading

0 comments on commit e38b6d0

Please sign in to comment.