Skip to content

Commit 56ac6ef

Browse files
tstaplerbobbypage
andcommitted
Add support for building multi-arch images
Only install libipmctl for amd64 versions of the docker image. Updated ipmctl to v02.00.00.3885 to fix intel/ipmctl#169 Updated base image to alpine:1.16 from alpine:1.15 to add zfs support on "arm" architecture. Co-authored-by: David Porter <[email protected]> Signed-of-by: Tyler Stapler <[email protected]>
1 parent 24e7a98 commit 56ac6ef

File tree

10 files changed

+233
-79
lines changed

10 files changed

+233
-79
lines changed

.gitignore

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -1,6 +1,7 @@
11
cadvisor
22
/release
33
.vscode
4+
_output/
45

56
# Log files
67
*.log

Makefile

Lines changed: 2 additions & 8 deletions
Original file line numberDiff line numberDiff line change
@@ -17,13 +17,6 @@ GOLANGCI_VER := v1.45.2
1717
GO_TEST ?= $(GO) test $(or $(GO_FLAGS),-race)
1818
arch ?= $(shell go env GOARCH)
1919

20-
ifeq ($(arch), amd64)
21-
Dockerfile_tag := ''
22-
else
23-
Dockerfile_tag := '.''$(arch)'
24-
endif
25-
26-
2720
all: presubmit build test
2821

2922
test:
@@ -76,7 +69,7 @@ release:
7669
@./build/release.sh
7770

7871
docker-%:
79-
@docker build -t cadvisor:$(shell git rev-parse --short HEAD) -f deploy/Dockerfile$(Dockerfile_tag) .
72+
@docker build -t cadvisor:$(shell git rev-parse --short HEAD) -f deploy/Dockerfile .
8073

8174
docker-build:
8275
@docker run --rm -w /go/src/github.com/google/cadvisor -v ${PWD}:/go/src/github.com/google/cadvisor golang:1.18 make build
@@ -99,5 +92,6 @@ lint:
9992

10093
clean:
10194
@rm -f *.test cadvisor
95+
@rm -rf _output/
10296

10397
.PHONY: all build docker format release test test-integration lint presubmit tidy

build/build.sh

Lines changed: 10 additions & 8 deletions
Original file line numberDiff line numberDiff line change
@@ -16,15 +16,17 @@
1616

1717
set -e
1818

19+
export GOOS=${GOOS:-$(go env GOOS)}
20+
export GOARCH=${GOARCH:-$(go env GOARCH)}
1921
GO_FLAGS=${GO_FLAGS:-"-tags netgo"} # Extra go flags to use in the build.
2022
BUILD_USER=${BUILD_USER:-"${USER}@${HOSTNAME}"}
2123
BUILD_DATE=${BUILD_DATE:-$( date +%Y%m%d-%H:%M:%S )}
2224
VERBOSE=${VERBOSE:-}
23-
GOARCH=$1
25+
OUTPUT_NAME_WITH_ARCH=${OUTPUT_NAME_WITH_ARCH:-"false"}
2426

2527
repo_path="github.com/google/cadvisor"
2628

27-
version=$( git describe --tags --dirty --abbrev=14 | sed -E 's/-([0-9]+)-g/.\1+/' )
29+
version=${VERSION:-$( git describe --tags --dirty --abbrev=14 | sed -E 's/-([0-9]+)-g/.\1+/' )}
2830
revision=$( git rev-parse --short HEAD 2> /dev/null || echo 'unknown' )
2931
branch=$( git rev-parse --abbrev-ref HEAD 2> /dev/null || echo 'unknown' )
3032
go_version=$( go version | sed -e 's/^[^0-9.]*\([0-9.]*\).*/\1/' )
@@ -50,15 +52,15 @@ if [ -n "$VERBOSE" ]; then
5052
echo "Building with -ldflags $ldflags"
5153
fi
5254

55+
mkdir -p "$PWD/_output"
56+
output_file="$PWD/_output/cadvisor"
57+
if [ "${OUTPUT_NAME_WITH_ARCH}" = "true" ] ; then
58+
output_file="${output_file}-${version}-${GOOS}-${GOARCH}"
59+
fi
60+
5361
# Since github.com/google/cadvisor/cmd is a submodule, we must build from inside that directory
54-
output_file="$PWD/cadvisor"
5562
pushd cmd > /dev/null
56-
if [ -z "$GOARCH" ]
57-
then
5863
go build ${GO_FLAGS} -ldflags "${ldflags}" -o "${output_file}" "${repo_path}/cmd"
59-
else
60-
env GOOS=linux GOARCH=$GOARCH go build ${GO_FLAGS} -ldflags "${ldflags}" -o "${output_file}" "${repo_path}/cmd"
61-
fi
6264
popd > /dev/null
6365

6466
exit 0

build/check_container.sh

Lines changed: 67 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,67 @@
1+
#!/usr/bin/env bash
2+
# Copyright 2015 Google Inc. All rights reserved.
3+
#
4+
# Licensed under the Apache License, Version 2.0 (the "License");
5+
# you may not use this file except in compliance with the License.
6+
# You may obtain a copy of the License at
7+
#
8+
# http://www.apache.org/licenses/LICENSE-2.0
9+
#
10+
# Unless required by applicable law or agreed to in writing, software
11+
# distributed under the License is distributed on an "AS IS" BASIS,
12+
# WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
13+
# See the License for the specific language governing permissions and
14+
# limitations under the License.
15+
#
16+
# Description:
17+
# This script is meant to run a basic test against each of the CPU architectures
18+
# cadvisor should support.
19+
#
20+
# This script requires that you have run qemu-user-static so that your machine
21+
# can interpret ELF binaries for other architectures using QEMU:
22+
# https://github.com/multiarch/qemu-user-static#getting-started
23+
#
24+
# $ docker run --rm --privileged multiarch/qemu-user-static --reset -p yes
25+
#
26+
# Usage:
27+
# ./check_container.sh gcr.io/tstapler-gke-dev/cadvisor:v0.44.1-test-4
28+
target_image=$1
29+
30+
# Architectures officially supported by cadvisor
31+
arches=( "amd64" "arm" "arm64" )
32+
33+
# Docker doesn't handle images with different architectures but the same tag.
34+
# Remove the container and the image use by it to avoid problems.
35+
cleanup() {
36+
echo Cleaning up the container $1
37+
docker stop $1
38+
docker rmi $target_image
39+
echo
40+
}
41+
42+
for arch in "${arches[@]}"; do
43+
echo Testing that we can run $1 on $arch and curl the /healthz endpoint
44+
echo
45+
container_id=$(docker run --platform "linux/$arch" -p 8080:8080 --rm --detach "$target_image")
46+
docker_exit_code=$?
47+
if [ $docker_exit_code -ne 0 ]; then
48+
echo Failed to run container docker exited with $docker_exit_code
49+
cleanup $container_id
50+
exit $docker_exit_code
51+
fi
52+
sleep 10
53+
echo
54+
echo Testing the container with curl:
55+
curl --show-error --retry 5 --fail -L 127.0.0.1:8080/healthz
56+
echo
57+
echo
58+
curl_exit=$?
59+
if [ $curl_exit -ne 0 ]; then
60+
echo Curling $target_image did not work
61+
cleanup $container_id
62+
exit $curl_exit
63+
fi
64+
echo Success!
65+
echo
66+
cleanup $container_id
67+
done

build/integration-in-docker.sh

Lines changed: 2 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -26,10 +26,10 @@ function delete() {
2626
rm -rf "${TMPDIR}"
2727
fi
2828
}
29-
trap delete EXIT INT
29+
trap delete EXIT INT TERM
3030

3131
function run_tests() {
32-
BUILD_CMD="env GOOS=linux GO_FLAGS='$GO_FLAGS' ./build/build.sh amd64 && \
32+
BUILD_CMD="env GOOS=linux GOARCH=amd64 GO_FLAGS='$GO_FLAGS' ./build/build.sh && \
3333
env GOOS=linux GOFLAGS='$GO_FLAGS' go test -c github.com/google/cadvisor/integration/tests/api && \
3434
env GOOS=linux GOFLAGS='$GO_FLAGS' go test -c github.com/google/cadvisor/integration/tests/healthz"
3535

build/integration.sh

Lines changed: 25 additions & 4 deletions
Original file line numberDiff line numberDiff line change
@@ -15,6 +15,16 @@
1515
# limitations under the License.
1616

1717
set -e
18+
# When running this script locally, you may need to run cadvisor with sudo
19+
# permissions if you cadvisor can't find containers.
20+
# USE_SUDO=true make test-integration
21+
USE_SUDO=${USE_SUDO:-false}
22+
cadvisor_bin=${CADVISOR_BIN:-"./_output/cadvisor"}
23+
24+
if ! [ -f "$cadvisor_bin" ]; then
25+
echo Failed to find cadvisor binary for integration test at path $cadvisor_bin
26+
exit 1
27+
fi
1828

1929
log_file="cadvisor.log"
2030
if [ "$#" -gt 0 ]; then
@@ -26,10 +36,16 @@ printf "" # Refresh sudo credentials if necessary.
2636
function start {
2737
set +e # We want to handle errors if cAdvisor crashes.
2838
echo ">> starting cAdvisor locally"
39+
cadvisor_prereqs=""
40+
if [ $USE_SUDO = true ]; then
41+
cadvisor_prereqs=sudo
42+
fi
2943
# cpu, cpuset, percpu, memory, disk, diskIO, network, perf_event metrics should be enabled.
30-
GORACE="halt_on_error=1" ./cadvisor --enable_metrics="cpu,cpuset,percpu,memory,disk,diskIO,network,perf_event" --env_metadata_whitelist=TEST_VAR --v=6 --logtostderr $CADVISOR_ARGS &> "$log_file"
31-
if [ $? != 0 ]; then
32-
echo "!! cAdvisor exited unexpectedly with Exit $?"
44+
GORACE="halt_on_error=1" $cadvisor_prereqs $cadvisor_bin --enable_metrics="cpu,cpuset,percpu,memory,disk,diskIO,network,perf_event" --env_metadata_whitelist=TEST_VAR --v=6 --logtostderr $CADVISOR_ARGS &> "$log_file"
45+
exit_code=$?
46+
if [ $exit_code != 0 ]; then
47+
echo "!! cAdvisor exited unexpectedly with Exit $exit_code"
48+
cat $log_file
3349
kill $TEST_PID # cAdvisor crashed: abort testing.
3450
fi
3551
}
@@ -43,7 +59,7 @@ function cleanup {
4359
wait $RUNNER_PID
4460
fi
4561
}
46-
trap cleanup EXIT
62+
trap cleanup EXIT SIGINT TERM
4763

4864
readonly TIMEOUT=30 # Timeout to wait for cAdvisor, in seconds.
4965
START=$(date +%s)
@@ -57,5 +73,10 @@ while [ "$(curl -Gs http://localhost:8080/healthz)" != "ok" ]; do
5773
done
5874

5975
echo ">> running integration tests against local cAdvisor"
76+
if ! [ -f ./api.test ] || ! [ -f ./healthz.test ]; then
77+
echo You must compile the ./api.test binary and ./healthz.test binary before
78+
echo running the integration tests.
79+
exit 1
80+
fi
6081
./api.test --vmodule=*=2 -test.v
6182
./healthz.test --vmodule=*=2 -test.v

build/release.sh

Lines changed: 51 additions & 25 deletions
Original file line numberDiff line numberDiff line change
@@ -16,12 +16,20 @@
1616

1717
set -e
1818

19-
VERSION=$( git describe --tags --dirty --abbrev=14 | sed -E 's/-([0-9]+)-g/.\1+/' )
20-
# Only allow releases of tagged versions.
21-
TAGGED='^v[0-9]+\.[0-9]+\.[0-9]+(-(alpha|beta|rc)\.?[0-9]*)?$'
22-
if [[ ! "$VERSION" =~ $TAGGED ]]; then
23-
echo "Error: Only tagged versions are allowed for releases" >&2
24-
echo "Found: $VERSION" >&2
19+
if [ -z "$VERSION" ]; then
20+
VERSION=$( git describe --tags --dirty --abbrev=14 | sed -E 's/-([0-9]+)-g/.\1+/' )
21+
# Only allow releases of tagged versions.
22+
TAGGED='^v[0-9]+\.[0-9]+\.[0-9]+(-(alpha|beta|rc)\.?[0-9]*)?$'
23+
if [[ ! "$VERSION" =~ $TAGGED ]]; then
24+
echo "Error: Only tagged versions are allowed for releases" >&2
25+
echo "Found: $VERSION" >&2
26+
exit 1
27+
fi
28+
fi
29+
30+
read -p "Please confirm: $VERSION is the desired version (Type y/n to continue):" -n 1 -r
31+
echo
32+
if ! [[ $REPLY =~ ^[Yy]$ ]]; then
2533
exit 1
2634
fi
2735

@@ -36,31 +44,49 @@ export BUILD_USER="$git_user"
3644
export BUILD_DATE=$( date +%Y%m%d ) # Release date is only to day-granularity
3745
export VERBOSE=true
3846

39-
# Build the release binary with libpfm4 for docker container
40-
export GO_FLAGS="-tags=libpfm,netgo"
41-
build/build.sh
42-
4347
# Build the docker image
4448
echo ">> building cadvisor docker image"
45-
gcr_tag="gcr.io/cadvisor/cadvisor:$VERSION"
46-
docker build -t $gcr_tag -f deploy/Dockerfile .
49+
image_name=${IMAGE_NAME:-"gcr.io/cadvisor/cadvisor"}
50+
final_image="$image_name:${VERSION}"
4751

48-
# Build the release binary without libpfm4 to not require libpfm4 in runtime environment
49-
unset GO_FLAGS
50-
build/build.sh
52+
docker buildx inspect cadvisor-builder > /dev/null \
53+
|| docker buildx create --name cadvisor-builder --use
5154

55+
# Build binaries
56+
57+
# A mapping of the docker arch name to the qemu arch name
58+
declare -A arches=( ["amd64"]="x86_64" ["arm"]="arm" ["arm64"]="aarch64")
59+
60+
for arch in "${arches[@]}"; do
61+
if ! hash "qemu-${arch}-static"; then
62+
echo Releasing multi arch containers requires qemu-user-static.
63+
echo
64+
echo Please install using apt-get install qemu-user-static or
65+
echo a similar package for your OS.
66+
67+
exit 1
68+
fi
69+
done
70+
71+
for arch in "${!arches[@]}"; do
72+
GOARCH="$arch" OUTPUT_NAME_WITH_ARCH="true" build/build.sh
73+
arch_specific_image="${image_name}-${arch}:${VERSION}"
74+
docker buildx build --platform "linux/${arch}" --build-arg VERSION="$VERSION" -f deploy/Dockerfile -t "$arch_specific_image" --progress plain --push .
75+
docker manifest create --amend "$final_image" "$arch_specific_image"
76+
docker manifest annotate --os=linux --arch="$arch" "$final_image" "$arch_specific_image"
77+
done
78+
docker manifest push "$final_image"
5279
echo
53-
echo "double-check the version below:"
54-
echo "VERSION=$VERSION"
55-
echo
56-
echo "To push docker image to gcr:"
57-
echo "docker push $gcr_tag"
80+
echo "Release info (copy to the release page)":
5881
echo
59-
echo "Release info (copy to the release page):"
82+
echo Multi Arch Container Image:
83+
echo $final_image
6084
echo
61-
echo "Docker Image: N/A"
62-
echo "gcr.io Image: $gcr_tag"
85+
echo Architecture Specific Container Images:
86+
for arch in "${!arches[@]}"; do
87+
echo "${image_name}-${arch}:${VERSION}"
88+
done
6389
echo
64-
sha256sum --tag cadvisor
65-
90+
echo Binaries:
91+
(cd _output && find . -name "cadvisor-${VERSION}*" -exec sha256sum --tag {} \;)
6692
exit 0

deploy/Dockerfile

Lines changed: 28 additions & 14 deletions
Original file line numberDiff line numberDiff line change
@@ -1,8 +1,9 @@
1-
FROM alpine:3.15 AS build
1+
FROM mirror.gcr.io/library/golang:1.18-alpine3.16 AS build
22

3-
RUN apk --no-cache add libc6-compat device-mapper findutils zfs build-base linux-headers python3 bash git wget cmake pkgconfig ndctl-dev && \
3+
# Install build depdencies for all supported arches
4+
RUN apk --no-cache add bash build-base cmake device-mapper findutils git \
5+
libc6-compat linux-headers ndctl-dev pkgconfig python3 wget zfs && \
46
apk --no-cache add thin-provisioning-tools --repository http://dl-3.alpinelinux.org/alpine/edge/main/ && \
5-
apk --no-cache add go==1.16.10-r0 --repository http://dl-3.alpinelinux.org/alpine/v3.14/community/ && \
67
echo 'hosts: files mdns4_minimal [NOTFOUND=return] dns mdns4' >> /etc/nsswitch.conf && \
78
rm -rf /var/cache/apk/*
89

@@ -15,35 +16,48 @@ RUN export DBG="-g -Wall" && \
1516
make -e -C libpfm-4.11.0 && \
1617
make install -C libpfm-4.11.0
1718

18-
RUN git clone -b v02.00.00.3820 https://github.com/intel/ipmctl/ && \
19+
# ipmctl only supports Intel x86_64 processors.
20+
# https://github.com/intel/ipmctl/issues/163
21+
RUN if [ "$(uname --machine)" = "x86_64" ]; then \
22+
git clone -b v02.00.00.3885 https://github.com/intel/ipmctl/ && \
1923
cd ipmctl && \
2024
mkdir output && \
2125
cd output && \
2226
cmake -DRELEASE=ON -DCMAKE_INSTALL_PREFIX=/ -DCMAKE_INSTALL_LIBDIR=/usr/local/lib .. && \
2327
make -j all && \
24-
make install
28+
make install; fi
2529

26-
ADD . /go/src/github.com/google/cadvisor
2730
WORKDIR /go/src/github.com/google/cadvisor
2831

29-
ENV GOROOT /usr/lib/go
30-
ENV GOPATH /go
31-
ENV GO_FLAGS="-tags=libpfm,netgo,libipmctl"
32+
# Cache Golang Dependencies for faster incremental builds
33+
ADD go.mod go.sum ./
34+
RUN go mod download
35+
ADD cmd/go.mod cmd/go.sum ./cmd/
36+
RUN cd cmd && go mod download
3237

33-
RUN ./build/build.sh
38+
ADD . .
3439

35-
FROM alpine:3.15
40+
ARG VERSION
41+
42+
# libipmctl only works on x86_64 CPUs.
43+
RUN export GO_TAGS="-tags=libfpm,netgo"; \
44+
if [ "$(uname --machine)" = "x86_64" ]; then \
45+
export GO_TAGS="$GO_TAGS,libipmctl"; \
46+
fi; \
47+
GO_FLAGS="-tags=$GO_TAGS" ./build/build.sh
48+
49+
FROM mirror.gcr.io/library/alpine:3.16
3650
3751

38-
RUN apk --no-cache add libc6-compat device-mapper findutils zfs ndctl && \
52+
RUN apk --no-cache add libc6-compat device-mapper findutils ndctl zfs && \
3953
apk --no-cache add thin-provisioning-tools --repository http://dl-3.alpinelinux.org/alpine/edge/main/ && \
4054
echo 'hosts: files mdns4_minimal [NOTFOUND=return] dns mdns4' >> /etc/nsswitch.conf && \
4155
rm -rf /var/cache/apk/*
4256

43-
# Grab cadvisor,libpfm4 and libipmctl from "build" container.
57+
# Grab cadvisor,libpfm4 and libipmctl from "build" container if they exist (libipmctl only works on amd64/x86_64).
4458
COPY --from=build /usr/local/lib/libpfm.so* /usr/local/lib/
4559
COPY --from=build /usr/local/lib/libipmctl.so* /usr/local/lib/
46-
COPY --from=build /go/src/github.com/google/cadvisor/cadvisor /usr/bin/cadvisor
60+
COPY --from=build /go/src/github.com/google/cadvisor/_output/cadvisor /usr/bin/cadvisor
4761

4862
EXPOSE 8080
4963

deploy/Dockerfile.ppc64le

Lines changed: 2 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -1,5 +1,7 @@
11
FROM ppc64le/alpine:3.15
22
3+
# Deprecated: the Dockerfile in this directory should support ppc64le
4+
# Simply build using: docker buildx build --platform linux/ppc64le -f Dockerfile .
35

46
RUN apk --no-cache add libc6-compat device-mapper findutils zfs && \
57
apk --no-cache add thin-provisioning-tools --repository http://dl-3.alpinelinux.org/alpine/edge/main/ && \

0 commit comments

Comments
 (0)