Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

Build Kubernetes UI from source. #8776

Closed
wants to merge 1 commit into from
Closed
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
2 changes: 2 additions & 0 deletions .gitignore
Original file line number Diff line number Diff line change
Expand Up @@ -54,5 +54,7 @@ network_closure.sh
# Web UI
www/master/node_modules/
www/master/npm-debug.log
www/master/shared/config/development.json

# Karma output
www/test_out
6 changes: 4 additions & 2 deletions build/build-image/Dockerfile
Original file line number Diff line number Diff line change
Expand Up @@ -25,9 +25,11 @@ ENV GOARCH amd64
# work around 64MB tmpfs size in Docker 1.6
ENV TMPDIR /tmp.k8s

# Get the code coverage tool and godep
# Get the code coverage tool, godep and binary data file builder
RUN mkdir $TMPDIR && \
go get golang.org/x/tools/cmd/cover github.com/tools/godep
go get golang.org/x/tools/cmd/cover && \
go get github.com/tools/godep && \
go get github.com/jteeuwen/go-bindata/...

# We use rsync to copy some binaries around. It is faster (0.3s vs. 1.1s) on my
# machine vs. `install`
Expand Down
124 changes: 98 additions & 26 deletions build/common.sh
Original file line number Diff line number Diff line change
Expand Up @@ -46,20 +46,26 @@ readonly KUBE_GCS_LATEST_CONTENTS=${KUBE_GCS_LATEST_CONTENTS:-}

# Constants
readonly KUBE_BUILD_IMAGE_REPO=kube-build
readonly KUBE_BUILD_UI_IMAGE_REPO=kube-build-ui
# These get set in verify_prereqs with a unique hash based on KUBE_ROOT
# KUBE_BUILD_IMAGE_TAG=<hash>
# KUBE_BUILD_IMAGE="${KUBE_BUILD_IMAGE_REPO}:${KUBE_BUILD_IMAGE_TAG}"
# KUBE_BUILD_CONTAINER_NAME=kube-build-<hash>
# KUBE_BUILD_UI_IMAGE="${KUBE_BUILD_UI_IMAGE_REPO}:${KUBE_BUILD_IMAGE_TAG}"
# KUBE_BUILD_UI_CONTAINER_NAME=kube-build-ui-<hash>
readonly KUBE_BUILD_IMAGE_CROSS_TAG=cross
readonly KUBE_BUILD_IMAGE_CROSS="${KUBE_BUILD_IMAGE_REPO}:${KUBE_BUILD_IMAGE_CROSS_TAG}"
readonly KUBE_BUILD_GOLANG_REPO=golang
readonly KUBE_BUILD_NODE_REPO=node
readonly KUBE_BUILD_GOLANG_VERSION=1.4
readonly KUBE_BUILD_NODE_VERSION=0.12.3
# KUBE_BUILD_DATA_CONTAINER_NAME=kube-build-data-<hash>

# Here we map the output directories across both the local and remote _output
# directories:
#
# *_OUTPUT_ROOT - the base of all output in that environment.
# *_OUTPUT_SUBPATH - location where golang stuff is built/cached. Also
# *_OUTPUT_SUBPATH - location where stuff is built/cached. Also
# persisted across docker runs with a volume mount.
# *_OUTPUT_BINPATH - location where final binaries are placed. If the remote
# is really remote, this is the stuff that has to be copied
Expand All @@ -71,22 +77,29 @@ readonly LOCAL_OUTPUT_IMAGE_STAGING="${LOCAL_OUTPUT_ROOT}/images"

readonly OUTPUT_BINPATH="${CUSTOM_OUTPUT_BINPATH:-$LOCAL_OUTPUT_BINPATH}"

readonly REMOTE_OUTPUT_ROOT="/go/src/${KUBE_GO_PACKAGE}/_output"
readonly REMOTE_SOURCE_ROOT="/go/src/${KUBE_GO_PACKAGE}"
readonly REMOTE_OUTPUT_ROOT="${REMOTE_SOURCE_ROOT}/_output"
readonly REMOTE_OUTPUT_SUBPATH="${REMOTE_OUTPUT_ROOT}/dockerized"
readonly REMOTE_OUTPUT_BINPATH="${REMOTE_OUTPUT_SUBPATH}/bin"

readonly DOCKER_MOUNT_ARGS_BASE=(--volume "${OUTPUT_BINPATH}:${REMOTE_OUTPUT_BINPATH}")
# DOCKER_MOUNT_ARGS=("${DOCKER_MOUNT_ARGS_BASE[@]}" --volumes-from "${KUBE_BUILD_DATA_CONTAINER_NAME}")

# We create a Docker data container to cache incremental build artifacts. We
# need to cache both the go tree in _output and the go tree under Godeps.
# need to cache both the go tree in _output and the go tree under Godeps. We
# also need to cache the output from the ui build.
readonly REMOTE_OUTPUT_GOPATH="${REMOTE_OUTPUT_SUBPATH}/go"
readonly REMOTE_GODEP_GOPATH="/go/src/${KUBE_GO_PACKAGE}/Godeps/_workspace/pkg"
readonly REMOTE_GODEP_GOPATH="${REMOTE_SOURCE_ROOT}/Godeps/_workspace/pkg"
readonly REMOTE_OUTPUT_WWWPATH="${REMOTE_OUTPUT_SUBPATH}/www"
readonly DOCKER_DATA_MOUNT_ARGS=(
--volume "${REMOTE_OUTPUT_GOPATH}"
--volume "${REMOTE_GODEP_GOPATH}"
--volume "${REMOTE_OUTPUT_WWWPATH}"
)

# Use the smallest image common to all build containers.
readonly KUBE_BUILD_DATA_IMAGE=buildpack-deps:jessie-scm

# This is where the final release artifacts are created locally
readonly RELEASE_STAGE="${LOCAL_OUTPUT_ROOT}/release-stage"
readonly RELEASE_DIR="${LOCAL_OUTPUT_ROOT}/release-tars"
Expand Down Expand Up @@ -114,6 +127,8 @@ readonly KUBE_DOCKER_WRAPPED_BINARIES=(
# KUBE_BUILD_IMAGE_TAG
# KUBE_BUILD_IMAGE
# KUBE_BUILD_CONTAINER_NAME
# KUBE_BUILD_UI_IMAGE
# KUBE_BUILD_UI_CONTAINER_NAME
# KUBE_BUILD_DATA_CONTAINER_NAME
# DOCKER_MOUNT_ARGS
function kube::build::verify_prereqs() {
Expand Down Expand Up @@ -167,9 +182,9 @@ function kube::build::verify_prereqs() {

# On OS X, set boot2docker env vars for the 'clean' target if boot2docker is running
if kube::build::is_osx && kube::build::has_docker ; then
if [[ ! -z "$(which boot2docker)" ]]; then
if [[ $(boot2docker status) == "running" ]]; then
if [[ -z "$DOCKER_HOST" ]]; then
if [[ -z "$DOCKER_HOST" ]]; then
if [[ ! -z "$(which boot2docker)" ]]; then
if [[ $(boot2docker status) == "running" ]]; then
kube::log::status "Setting boot2docker env variables"
$(boot2docker shellinit)
fi
Expand All @@ -183,6 +198,9 @@ function kube::build::verify_prereqs() {
KUBE_BUILD_IMAGE_TAG="build-${KUBE_ROOT_HASH}"
KUBE_BUILD_IMAGE="${KUBE_BUILD_IMAGE_REPO}:${KUBE_BUILD_IMAGE_TAG}"
KUBE_BUILD_CONTAINER_NAME="kube-build-${KUBE_ROOT_HASH}"
KUBE_BUILD_UI_IMAGE_TAG="${KUBE_BUILD_IMAGE_TAG}"
KUBE_BUILD_UI_IMAGE="${KUBE_BUILD_UI_IMAGE_REPO}:${KUBE_BUILD_UI_IMAGE_TAG}"
KUBE_BUILD_UI_CONTAINER_NAME="kube-build-ui-${KUBE_ROOT_HASH}"
KUBE_BUILD_DATA_CONTAINER_NAME="kube-build-data-${KUBE_ROOT_HASH}"
DOCKER_MOUNT_ARGS=("${DOCKER_MOUNT_ARGS_BASE[@]}" --volumes-from "${KUBE_BUILD_DATA_CONTAINER_NAME}")
}
Expand Down Expand Up @@ -287,10 +305,10 @@ function kube::build::build_image_built() {
kube::build::docker_image_exists "${KUBE_BUILD_IMAGE_REPO}" "${KUBE_BUILD_IMAGE_TAG}"
}

function kube::build::ensure_golang() {
kube::build::docker_image_exists golang "${KUBE_BUILD_GOLANG_VERSION}" || {
function kube::build::ensure_docker_image() {
kube::build::docker_image_exists $1 $2 || {
[[ ${KUBE_SKIP_CONFIRMATIONS} =~ ^[yY]$ ]] || {
echo "You don't have a local copy of the golang docker image. This image is 450MB."
echo "You don't have a local copy of the $1 docker image."
read -p "Download it now? [y/n] " -r
echo
[[ $REPLY =~ ^[yY]$ ]] || {
Expand All @@ -299,11 +317,19 @@ function kube::build::ensure_golang() {
}
}

kube::log::status "Pulling docker image: golang:${KUBE_BUILD_GOLANG_VERSION}"
"${DOCKER[@]}" pull golang:${KUBE_BUILD_GOLANG_VERSION}
kube::log::status "Pulling docker image: $1:$2"
"${DOCKER[@]}" pull $1:$2
}
}

function kube::build::ensure_golang() {
kube::build::ensure_docker_image "${KUBE_BUILD_GOLANG_REPO}" "${KUBE_BUILD_GOLANG_VERSION}"
}

function kube::build::ensure_node() {
kube::build::ensure_docker_image "${KUBE_BUILD_NODE_REPO}" "${KUBE_BUILD_NODE_VERSION}"
}

# Set up the context directory for the kube-build image and build it.
function kube::build::build_image() {
local -r build_context_dir="${LOCAL_OUTPUT_IMAGE_STAGING}/${KUBE_BUILD_IMAGE}"
Expand All @@ -316,6 +342,7 @@ function kube::build::build_image() {
Godeps/_workspace/src
Godeps/Godeps.json
hack
hooks
LICENSE
pkg
plugin
Expand All @@ -340,12 +367,36 @@ function kube::build::build_image() {
function kube::build::build_image_cross() {
kube::build::ensure_golang

local -r build_context_dir="${LOCAL_OUTPUT_ROOT}/images/${KUBE_BUILD_IMAGE}/cross"
local -r build_context_dir="${LOCAL_OUTPUT_IMAGE_STAGING}/${KUBE_BUILD_IMAGE}/cross"
mkdir -p "${build_context_dir}"
cp build/build-image/cross/Dockerfile ${build_context_dir}/Dockerfile
kube::build::docker_build "${KUBE_BUILD_IMAGE_CROSS}" "${build_context_dir}"
}

# Set up the context directory for the kube-build-ui image and build it.
function kube::build::build_ui_image() {
kube::build::ensure_node

local -r build_context_dir="${LOCAL_OUTPUT_IMAGE_STAGING}/${KUBE_BUILD_UI_IMAGE}"
local -r source=(
build
hack
hooks
LICENSE
README.md
www
)

mkdir -p "${build_context_dir}"
tar czf "${build_context_dir}/kube-ui-source.tar.gz" "${source[@]}"

kube::version::get_version_vars
kube::version::save_version_vars "${build_context_dir}/kube-version-defs"

cp build/ui/build-image/Dockerfile ${build_context_dir}/Dockerfile
kube::build::docker_build "${KUBE_BUILD_UI_IMAGE}" "${build_context_dir}"
}

# Build a docker image from a Dockerfile.
# $1 is the name of the image to build
# $2 is the location of the "context" directory, with the Dockerfile at the root.
Expand Down Expand Up @@ -382,37 +433,44 @@ function kube::build::clean_images() {
kube::build::has_docker || return 0

kube::build::clean_image "${KUBE_BUILD_IMAGE}"
kube::build::clean_image "${KUBE_BUILD_UI_IMAGE}"

kube::log::status "Cleaning all other untagged docker images"
"${DOCKER[@]}" rmi $("${DOCKER[@]}" images -q --filter 'dangling=true') 2> /dev/null || true
}

# Build the data container to cache incremental build artifacts.
function kube::build::ensure_data_container() {
if ! "${DOCKER[@]}" inspect "${KUBE_BUILD_DATA_CONTAINER_NAME}" >/dev/null 2>&1; then
kube::log::status "Creating data container"
local -ra docker_cmd=(
"${DOCKER[@]}" run
"${DOCKER_DATA_MOUNT_ARGS[@]}"
--name "${KUBE_BUILD_DATA_CONTAINER_NAME}"
"${KUBE_BUILD_IMAGE}"
"${KUBE_BUILD_DATA_IMAGE}"
true
)
"${docker_cmd[@]}"
fi
}

# Run a command in the kube-build image. This assumes that the image has
# already been built. This will sync out all output data from the build.
function kube::build::run_build_command() {
kube::log::status "Running build command...."
[[ $# != 0 ]] || { echo "Invalid input." >&2; return 4; }
# Run a command in the supplied image. This assumes that the image has
# already been built.
# $1 is the name of the container to create
# $2 is the name of the image to use.
function kube::build::run_containerized_command() {
[[ $# > 2 ]] || { echo "Invalid input." >&2; return 4; }

local docker_image="$1"
local docker_container="$2"
shift 2

kube::build::ensure_data_container
kube::build::prepare_output
kube::build::prepare_output

local -a docker_run_opts=(
"--name=${KUBE_BUILD_CONTAINER_NAME}"
"${DOCKER_MOUNT_ARGS[@]}"
"--name=$docker_container"
"${DOCKER_MOUNT_ARGS[@]}"
)

# If we have stdin we can run interactive. This allows things like 'shell.sh'
Expand All @@ -426,19 +484,33 @@ function kube::build::run_build_command() {
fi

local -ra docker_cmd=(
"${DOCKER[@]}" run "${docker_run_opts[@]}" "${KUBE_BUILD_IMAGE}")
"${DOCKER[@]}" run "${docker_run_opts[@]}" "$docker_image")

# Clean up container from any previous run
kube::build::destroy_container "${KUBE_BUILD_CONTAINER_NAME}"
kube::build::destroy_container "$docker_container"
"${docker_cmd[@]}" "$@"
kube::build::destroy_container "${KUBE_BUILD_CONTAINER_NAME}"
kube::build::destroy_container "$docker_container"
}

# Run a command in the kube-build image. This assumes that the image has
# already been built. This will sync out all output data from the build.
function kube::build::run_build_command() {
kube::log::status "Running build command...."
kube::build::run_containerized_command "${KUBE_BUILD_IMAGE}" "${KUBE_BUILD_CONTAINER_NAME}" "$@"
}

# Run a command in the kube-build-ui image. This assumes that the image has
# already been built.
function kube::build::run_build_ui_command() {
kube::log::status "Running build ui command...."
kube::build::run_containerized_command "${KUBE_BUILD_UI_IMAGE}" "${KUBE_BUILD_UI_CONTAINER_NAME}" "$@"
}

# Test if the output directory is remote (and can only be accessed through
# docker) or if it is "local" and we can access the output without going through
# docker.
function kube::build::is_output_remote() {
rm -f "${LOCAL_OUTPUT_SUBPATH}/test_for_remote"
rm -f "${LOCAL_OUTPUT_BINPATH}/test_for_remote"
kube::build::run_build_command touch "${REMOTE_OUTPUT_BINPATH}/test_for_remote"

[[ ! -e "${LOCAL_OUTPUT_BINPATH}/test_for_remote" ]]
Expand Down
4 changes: 4 additions & 0 deletions build/release.sh
Original file line number Diff line number Diff line change
Expand Up @@ -28,6 +28,10 @@ source "$KUBE_ROOT/build/common.sh"
KUBE_RELEASE_RUN_TESTS=${KUBE_RELEASE_RUN_TESTS-y}

kube::build::verify_prereqs

kube::build::build_ui_image
kube::build::run_build_ui_command hack/ui/build-www.sh

kube::build::build_image
kube::build::run_build_command hack/build-cross.sh

Expand Down
38 changes: 38 additions & 0 deletions build/ui/build-image/Dockerfile
Original file line number Diff line number Diff line change
@@ -0,0 +1,38 @@
# Copyright 2014 Google Inc. All rights reserved.
#
# 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.

# This file creates a standard build environment for building the Kubernetes WebUI

FROM node:0.12.3
MAINTAINER Jack Greenfield <jackgr@google.com>

# work around 64MB tmpfs size in Docker 1.6
ENV TMPDIR /tmp.k8s-ui
RUN mkdir $TMPDIR

# Mark this as a kube-build-ui container
RUN touch /kube-build-ui-image

WORKDIR /go/src/github.com/GoogleCloudPlatform/kubernetes

# Propagate the git tree version into the build image
ADD kube-version-defs /kube-version-defs
ENV KUBE_GIT_VERSION_FILE /kube-version-defs

# Make output from the dockerized build go someplace else
ENV KUBE_OUTPUT_SUBPATH _output/dockerized

# Upload Kubernetes WebUI source
ADD kube-ui-source.tar.gz /go/src/github.com/GoogleCloudPlatform/kubernetes

30 changes: 30 additions & 0 deletions build/ui/run.sh
Original file line number Diff line number Diff line change
@@ -0,0 +1,30 @@
#!/bin/bash

# Copyright 2014 The Kubernetes Authors All rights reserved.
#
# 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.

# Run a command in the Docker ui build container. Typically this will be one of
# the commands in `hack/ui`. When running in the ui build container the user is sure
# to have a consistent reproducible build environment.

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

KUBE_ROOT=$(dirname "${BASH_SOURCE}")/../..
source "$KUBE_ROOT/build/common.sh"

kube::build::verify_prereqs
kube::build::build_ui_image
kube::build::run_build_ui_command "$@"
Loading