[go: nahoru, domu]

Skip to content
This repository has been archived by the owner on May 30, 2024. It is now read-only.

Commit

Permalink
Merge pull request #102 from turkenh/local-dev-tooling
Browse files Browse the repository at this point in the history
Add Local Development Targets
  • Loading branch information
turkenh committed Aug 7, 2020
2 parents 276b947 + 3babcb9 commit 0eb3a91
Show file tree
Hide file tree
Showing 10 changed files with 530 additions and 1 deletion.
16 changes: 16 additions & 0 deletions README.md
Original file line number Diff line number Diff line change
Expand Up @@ -62,6 +62,22 @@ make -j tests

To see the help run `make help`.

## Local Development Setup

To use local development targets, first include `deploy.mk` in your make file:

```
include build/makelib/local.mk
```

Then, run the following command to initialize a local development configuration:

```
make local.scaffold
```

You can now configure and add more components (i.e. helm releases) to your local development setup.

## Contributing

We welcome contributions. See [Contributing](CONTRIBUTING.md) to get started.
Expand Down
2 changes: 1 addition & 1 deletion makelib/helm.mk
Original file line number Diff line number Diff line change
Expand Up @@ -40,7 +40,7 @@ HELM_HOME := $(abspath $(WORK_DIR)/helm)
export HELM_HOME

# helm tool version
HELM_VERSION ?= v2.15.1
HELM_VERSION ?= v2.16.7
HELM := $(TOOLS_HOST_DIR)/helm-$(HELM_VERSION)

# remove the leading `v` for helm chart versions
Expand Down
1 change: 1 addition & 0 deletions makelib/k8s_tools.mk
Original file line number Diff line number Diff line change
Expand Up @@ -43,6 +43,7 @@ build.vars: k8s_tools.buildvars
# kind download and install
$(KIND):
@$(INFO) installing kind $(KIND_VERSION)
@mkdir -p $(TOOLS_HOST_DIR) || $(FAIL)
@curl -fsSLo $(KIND) https://github.com/kubernetes-sigs/kind/releases/download/$(KIND_VERSION)/kind-$(GOHOSTOS)-$(GOHOSTARCH) || $(FAIL)
@chmod +x $(KIND)
@$(OK) installing kind $(KIND_VERSION)
Expand Down
147 changes: 147 additions & 0 deletions makelib/local.mk
Original file line number Diff line number Diff line change
@@ -0,0 +1,147 @@
SELF_DIR := $(dir $(lastword $(MAKEFILE_LIST)))
SCRIPTS_DIR := $(SELF_DIR)/../scripts

KIND_CLUSTER_NAME ?= local-dev

DEPLOY_LOCAL_DIR ?= $(ROOT_DIR)/cluster/local
DEPLOY_LOCAL_WORKDIR := $(WORK_DIR)/local/localdev
DEPLOY_LOCAL_CONFIG_DIR := $(DEPLOY_LOCAL_WORKDIR)/config
DEPLOY_LOCAL_KUBECONFIG := $(DEPLOY_LOCAL_WORKDIR)/kubeconfig
KIND_CONFIG_FILE := $(DEPLOY_LOCAL_WORKDIR)/kind.yaml
KUBECONFIG ?= $(HOME)/.kube/config

LOCAL_BUILD ?= true

export KIND
export KUBECTL
export HELM
export GOMPLATE
export BUILD_REGISTRY
export ROOT_DIR
export SCRIPTS_DIR
export KIND_CLUSTER_NAME
export WORK_DIR
export LOCALDEV_INTEGRATION_CONFIG_REPO
export DEPLOY_LOCAL_DIR
export DEPLOY_LOCAL_WORKDIR
export DEPLOY_LOCAL_CONFIG_DIR
export DEPLOY_LOCAL_KUBECONFIG
export KIND_CONFIG_FILE
export KUBECONFIG
export LOCAL_BUILD
export HELM_OUTPUT_DIR
export BUILD_HELM_CHART_VERSION=$(HELM_CHART_VERSION)
export BUILD_HELM_CHARTS_LIST=$(HELM_CHARTS)
export BUILD_REGISTRIES=$(REGISTRIES)
export BUILD_IMAGES=$(IMAGES)
export BUILD_IMAGE_ARCHS=$(subst linux_,,$(filter linux_%,$(BUILD_PLATFORMS)))

# Install gomplate
GOMPLATE_VERSION := 3.7.0
GOMPLATE := $(TOOLS_HOST_DIR)/gomplate-$(GOMPLATE_VERSION)

gomplate.buildvars:
@echo GOMPLATE=$(GOMPLATE)

build.vars: gomplate.buildvars

$(GOMPLATE):
@$(INFO) installing gomplate $(HOSTOS)-$(HOSTARCH)
@curl -fsSLo $(GOMPLATE) https://github.com/hairyhenderson/gomplate/releases/download/v$(GOMPLATE_VERSION)/gomplate_$(HOSTOS)-$(HOSTARCH) || $(FAIL)
@chmod +x $(GOMPLATE)
@$(OK) installing gomplate $(HOSTOS)-$(HOSTARCH)

kind.up: $(KIND)
@$(INFO) kind up
@$(KIND) get kubeconfig --name $(KIND_CLUSTER_NAME) >/dev/null 2>&1 || $(KIND) create cluster --name=$(KIND_CLUSTER_NAME) --config="$(KIND_CONFIG_FILE)" --kubeconfig="$(KUBECONFIG)"
@$(KIND) get kubeconfig --name $(KIND_CLUSTER_NAME) > $(DEPLOY_LOCAL_KUBECONFIG)
@$(OK) kind up

kind.down: $(KIND)
@$(INFO) kind down
@$(KIND) delete cluster --name=$(KIND_CLUSTER_NAME)
@$(OK) kind down

kind.setcontext: $(KUBECTL)
@$(KUBECTL) --kubeconfig $(KUBECONFIG) config use-context kind-$(KIND_CLUSTER_NAME)

kind.buildvars:
@echo DEPLOY_LOCAL_KUBECONFIG=$(DEPLOY_LOCAL_KUBECONFIG)

build.vars: kind.buildvars
clean: local.down

.PHONY: kind.up kind.down kind.setcontext kind.buildvars

local.helminit: $(KUBECTL) $(HELM) kind.setcontext
@$(INFO) helm init
@docker pull gcr.io/kubernetes-helm/tiller:$(HELM_VERSION)
@$(KIND) load docker-image gcr.io/kubernetes-helm/tiller:$(HELM_VERSION) --name=$(KIND_CLUSTER_NAME)
@$(KUBECTL) --kubeconfig $(KUBECONFIG) --namespace kube-system get serviceaccount tiller > /dev/null 2>&1 || $(KUBECTL) --kubeconfig $(KUBECONFIG) --namespace kube-system create serviceaccount tiller
@$(KUBECTL) --kubeconfig $(KUBECONFIG) get clusterrolebinding tiller-cluster-rule > /dev/null 2>&1 || $(KUBECTL) --kubeconfig $(KUBECONFIG) create clusterrolebinding tiller-cluster-rule --clusterrole=cluster-admin --serviceaccount=kube-system:tiller
@$(HELM) ls > /dev/null 2>&1 || $(HELM) init --kubeconfig $(KUBECONFIG) --service-account tiller --upgrade --wait
@$(HELM) repo update
@$(OK) helm init

local.prepare:
@$(INFO) preparing local dev workdir
@$(SCRIPTS_DIR)/localdev-prepare.sh || $(FAIL)
@$(OK) preparing local dev workdir

local.clean:
@$(INFO) cleaning local dev workdir
@rm -rf $(WORK_DIR)/local || $(FAIL)
@$(OK) cleaning local dev workdir

local.up: local.prepare kind.up local.helminit

local.down: local.clean kind.down

local.deploy.%: $(KUBECTL) $(HELM) $(HELM_HOME) $(GOMPLATE) kind.setcontext
@$(INFO) localdev deploy component: $*
@$(eval PLATFORMS=$(BUILD_PLATFORMS))
@$(SCRIPTS_DIR)/localdev-deploy-component.sh $* || $(FAIL)
@$(OK) localdev deploy component: $*

local.remove.%: $(KUBECTL) $(HELM) $(HELM_HOME) $(GOMPLATE) kind.setcontext
@$(INFO) localdev remove component: $*
@$(SCRIPTS_DIR)/localdev-remove-component.sh $* || $(FAIL)
@$(OK) localdev remove component: $*

local.scaffold:
@$(INFO) localdev scaffold config
@$(SCRIPTS_DIR)/localdev-scaffold.sh || $(FAIL)
@$(OK) localdev scaffold config

.PHONY: local.helminit local.up local.deploy.% local.remove.% local.scaffold

# ====================================================================================
# Special Targets

fmt: go.imports
fmt.simplify: go.fmt.simplify
imports: go.imports
imports.fix: go.imports.fix
vendor: go.vendor
vendor.check: go.vendor.check
vendor.update: go.vendor.update
vet: go.vet
generate codegen: go.generate

define LOCAL_HELPTEXT
Local Targets:
local.scaffold scaffold a local development configuration
local.up stand up of a local development cluster with kind
local.down tear down local development cluster
local.deploy.% install/upgrade a local/external component, for example, local.deploy.crossplane
local.remove.% removes component, for example, local.remove.crossplane

endef
export LOCAL_HELPTEXT

local.help:
@echo "$$LOCAL_HELPTEXT"

help-special: local.help

###
46 changes: 46 additions & 0 deletions scripts/load-configs.sh
Original file line number Diff line number Diff line change
@@ -0,0 +1,46 @@
COMPONENT=$1

# REQUIRED_IMAGES is the array of images that the COMPONENT needs.
# These images will be pulled (if not exists) and loaded into the kind cluster before deployment.
# If an image has tags, it will be used.
# If an image does not have a tag, "v${HELM_CHART_VERSION}" will be used as a tag.
REQUIRED_IMAGES=()

# HELM_CHART_NAME is the name of the helm chart to deploy. If not set, defaults to COMPONENT
HELM_CHART_NAME=""
# HELM_CHART_VERSION is the version of the helm chart to deploy.
# If LOCAL_BUILD=true, HELM_CHART_VERSION will be set the version in build system.
# If LOCAL_BUILD=false, HELM_CHART_VERSION defaults to latest version in the HELM_REPOSITORY
HELM_CHART_VERSION=""
# HELM_REPOSITORY_NAME is the name of the helm repository.
# This will only be used if LOCAL_BUILD=false or HELM_CHART_NAME is not a local chart (e.g. not in HELM_CHARTS array)
HELM_REPOSITORY_NAME=""
# HELM_REPOSITORY_NAME is the url of the helm repository.
HELM_REPOSITORY_URL=""
# HELM_REPOSITORY_FORCE_UPDATE controls whether always update helm repositories or not.
# If false, "helm repo update" will only be called if repo does not exist already.
HELM_REPOSITORY_FORCE_UPDATE="false"
# HELM_RELEASE_NAME is the name of the helm release. If not set, defaults to COMPONENT
HELM_RELEASE_NAME=""
# HELM_RELEASE_NAMESPACE is the namespace for the helm release.
HELM_RELEASE_NAMESPACE="default"
# HELM_DELETE_ON_FAILURE controls whether to delete/rollback a failed install/upgrade.
HELM_DELETE_ON_FAILURE="true"

# COMPONENT_SKIP_DEPLOY controls whether (conditionally) skip deployment of a component or not.
COMPONENT_SKIP_DEPLOY="false"

MAIN_CONFIG_FILE="${DEPLOY_LOCAL_CONFIG_DIR}/config.env"
COMPONENT_CONFIG_DIR="${DEPLOY_LOCAL_CONFIG_DIR}/${COMPONENT}"
COMPONENT_CONFIG_FILE="${COMPONENT_CONFIG_DIR}/config.env"

if [[ ! -d "${COMPONENT_CONFIG_DIR}" ]]; then
echo_error "Component config dir \"${COMPONENT_CONFIG_DIR}\" does not exist (or is not a directory), did you run make local.prepare ?"
fi

if [[ -f "${MAIN_CONFIG_FILE}" ]]; then
source "${MAIN_CONFIG_FILE}"
fi
if [[ -f "${COMPONENT_CONFIG_FILE}" ]]; then
source "${COMPONENT_CONFIG_FILE}"
fi
131 changes: 131 additions & 0 deletions scripts/localdev-deploy-component.sh
Original file line number Diff line number Diff line change
@@ -0,0 +1,131 @@
#!/usr/bin/env bash
set -aeuo pipefail

COMPONENT=$1

# Source utility functions
source "${SCRIPTS_DIR}/utils.sh"
# sourcing load-configs.sh:
# - initializes configuration variables with default values
# - loads top level configuration
# - loads component level configuration
source "${SCRIPTS_DIR}/load-configs.sh" "${COMPONENT}"

# Skip deployment of this component if COMPONENT_SKIP_DEPLOY is set to true
if [ "${COMPONENT_SKIP_DEPLOY}" == "true" ]; then
echo "COMPONENT_SKIP_DEPLOY set to true, skipping deployment of ${COMPONENT}"
exit 0
fi

# if HELM_CHART_NAME is not set, default to component name
if [ -z "${HELM_CHART_NAME}" ]; then
HELM_CHART_NAME="${COMPONENT}"
fi

registries_arr=($BUILD_REGISTRIES)
images_arr=($BUILD_IMAGES)
image_archs_arr=($BUILD_IMAGE_ARCHS)
charts_arr=($BUILD_HELM_CHARTS_LIST)

if [ "${LOCAL_BUILD}" == "true" ] && containsElement "${HELM_CHART_NAME}" "${charts_arr[@]}"; then
# If local build is set and helm chart is from this repository, use locally build helm chart tgz file.
echo "Deploying locally built artifacts..."
HELM_CHART_VERSION=${BUILD_HELM_CHART_VERSION}
HELM_CHART_REF="${HELM_OUTPUT_DIR}/${COMPONENT}-${HELM_CHART_VERSION}.tgz"
[ -f "${HELM_CHART_REF}" ] || echo_error "Local chart ${HELM_CHART_REF} not found. Did you run \"make build\" ? "

# If local build, tag "required" local images, so that they can be load into kind cluster at a later step.
for r in "${registries_arr[@]}"; do
for i in "${images_arr[@]}"; do
for a in "${image_archs_arr[@]}"; do
if containsElement "${r}/${i}" "${REQUIRED_IMAGES[@]}"; then
echo "Tagging locally built image as ${r}/${i}:${VERSION}"
docker tag "${BUILD_REGISTRY}/${i}-${a}" "${r}/${i}:${VERSION}"
fi
done
done
done
else
# If local build is NOT set or helm chart is NOT from this repository, deploy chart from a remote repository.
echo "Deploying latest artifacts in chart repo \"${HELM_REPOSITORY_NAME}\"..."
if [ -z ${HELM_REPOSITORY_NAME} ] || [ -z ${HELM_CHART_NAME} ]; then
echo_error "HELM_REPOSITORY_NAME and/or HELM_CHART_NAME is not set for component ${COMPONENT}!"
fi
HELM_CHART_REF="${HELM_REPOSITORY_NAME}/${HELM_CHART_NAME}"
# Add helm repo and update repositories, if repo is not added already or force update is set.
if [ "${HELM_REPOSITORY_FORCE_UPDATE}" == "true" ] || ! "${HELM}" repo list -o yaml |grep "Name:\s*${HELM_REPOSITORY_NAME}\s*$" >/dev/null; then
"${HELM}" repo add "${HELM_REPOSITORY_NAME}" "${HELM_REPOSITORY_URL}"
"${HELM}" repo update
fi
if [ -z "${HELM_CHART_VERSION}" ]; then
# if no HELM_CHART_VERSION provided, then get the latest version from repo which will be used to load required images for chart.
HELM_CHART_VERSION=$("${HELM}" search -l ${HELM_CHART_REF} --devel |awk 'NR==2{print $2}')
echo "Latest version found in repo: ${HELM_CHART_VERSION}"
fi
if [ -z "${HELM_CHART_VERSION}" ]; then
echo_error "No version found in repo for chart ${HELM_CHART_REF}"
fi
fi

# shellcheck disable=SC2068
for i in ${REQUIRED_IMAGES[@]+"${REQUIRED_IMAGES[@]}"}; do
# check if image has a tag, if not, append tag for the chart
if ! echo "${i}" | grep ":"; then
i="${i}:v${HELM_CHART_VERSION}"
fi
# Pull the image:
# - if has a tag "master" or "latest"
# - or does not exist already.
if echo "${i}" | grep ":master\s*$" >/dev/null || echo "${i}" | grep ":latest\s*$" >/dev/null || ! docker inspect --type=image "${i}" >/dev/null 2>&1; then
docker pull "${i}"
fi
"${KIND}" load docker-image "${i}" --name="${KIND_CLUSTER_NAME}"
done


PREDEPLOY_SCRIPT="${DEPLOY_LOCAL_CONFIG_DIR}/${COMPONENT}/pre-deploy.sh"
POSTDEPLOY_SCRIPT="${DEPLOY_LOCAL_CONFIG_DIR}/${COMPONENT}/post-deploy.sh"

# Run config.validate.sh if exists.
test -f "${DEPLOY_LOCAL_CONFIG_DIR}/config.validate.sh" && source "${DEPLOY_LOCAL_CONFIG_DIR}/config.validate.sh"

# Create the HELM_RELEASE_NAMESPACE if not exist already.
"${KUBECTL}" --kubeconfig "${KUBECONFIG}" get ns "${HELM_RELEASE_NAMESPACE}" >/dev/null 2>&1 || ${KUBECTL} \
--kubeconfig "${KUBECONFIG}" create ns "${HELM_RELEASE_NAMESPACE}"

# Run pre-deploy script, if exists.
if [ -f "${PREDEPLOY_SCRIPT}" ]; then
source "${PREDEPLOY_SCRIPT}"
fi

# With all configuration sourced as environment variables, render value-overrides.yaml file with gomplate.
"${GOMPLATE}" -f "${DEPLOY_LOCAL_CONFIG_DIR}/${COMPONENT}/value-overrides.yaml.tmpl" \
-o "${DEPLOY_LOCAL_CONFIG_DIR}/${COMPONENT}/value-overrides.yaml"

helm_chart_version_flag="--devel"
if [ -n "${HELM_CHART_VERSION}" ]; then
helm_chart_version_flag="--version ${HELM_CHART_VERSION}"
fi

helm_wait_atomic_flag="--wait"
if [ "${HELM_DELETE_ON_FAILURE}" == "true" ]; then
helm_wait_atomic_flag="--atomic"
fi

# if HELM_RELEASE_NAME is not set, default to component name
if [ -z "${HELM_RELEASE_NAME}" ]; then
HELM_RELEASE_NAME=${COMPONENT}
fi

# Run helm upgrade --install with computed parameters.
# shellcheck disable=SC2086
set -x
"${HELM}" upgrade --install "${HELM_RELEASE_NAME}" --namespace "${HELM_RELEASE_NAMESPACE}" --kubeconfig "${KUBECONFIG}" \
"${HELM_CHART_REF}" ${helm_chart_version_flag:-} -f "${DEPLOY_LOCAL_CONFIG_DIR}/${COMPONENT}/value-overrides.yaml" \
${helm_wait_atomic_flag:-} --force
{ set +x; } 2>/dev/null

# Run post-deploy script, if exists.
if [ -f "${POSTDEPLOY_SCRIPT}" ]; then
source "${POSTDEPLOY_SCRIPT}"
fi
Loading

0 comments on commit 0eb3a91

Please sign in to comment.