diff --git a/README.md b/README.md index c17a85c..77d0cb7 100644 --- a/README.md +++ b/README.md @@ -28,7 +28,23 @@ Then, launch the Kubernetes cluster in boot2docker via Docker Machine: ./kube-up.sh ``` -The script will set up port forwarding so that you can use kubectl locally without having to ssh into boot2docker. The default password for the boot2docker docker user is `tcuser`. +The script will set up port forwarding so that you can use kubectl locally without having to ssh into boot2docker. + +## Controlling Addons (DNS, UI) +You can use the the following options to disable specific additional services. The default is +to start all addons, __except__ the local Docker Registry: + +``` +Usage: kube-up.sh [-fndursh] +Available options are: + -f disable forward to port 8080 on docker machine (required for kubectl) + -n disable adding route to enable local name resolution via skyDNS + -d disable skyDNS + -u disable kube-ui + -r start local docker registry + -h show this help text + -s silent mode +``` ## Checking if Kubernetes Is Running diff --git a/common.sh b/common.sh new file mode 100644 index 0000000..e72752f --- /dev/null +++ b/common.sh @@ -0,0 +1,24 @@ +# colors +red=$(tput setaf 1) +green=$(tput setaf 2) +yellow=$(tput setaf 3) +reset=$(tput sgr0) + +# icons +checkmark="\xE2\x9C\x93" +warning="\xE2\x9A\xA0" +error="\xE2\x9C\x97" + +# helpers todo this should be somewhere else; or rename the settings file into 'common.sh' +function check_rc { + success_message=$1 + error_message=$2 + if [ $? -eq 0 ]; then + printf "\n${green} ${checkmark} $success_message ${reset}\n\n" + else + printf "\n${red} ${error} $error_message ${reset}\n\n" + fi +} + + + diff --git a/kube-down.sh b/kube-down.sh index d768c65..c982218 100755 --- a/kube-down.sh +++ b/kube-down.sh @@ -1,8 +1,12 @@ #!/bin/bash -echo "Stopping replication controllers, services and pods..." -kubectl stop replicationcontrollers,services,pods --all + +source ./common.sh + +printf "${yellow}Stopping replication controllers, services and pods...${reset}\n" + +kubectl stop replicationcontrollers,services,pods --all &> /dev/null if [ $? != 0 ]; then - echo "Kubernetes already down?" + printf "\n${yellow} ${warning} Cannot contact API server. Kubernetes already down? ${reset}\n\n" fi cd kubernetes @@ -14,7 +18,13 @@ fi k8s_containers=`docker ps -a -f "name=k8s_" -q` if [ ! -z "$k8s_containers" ]; then - echo "Stopping and removing all other containers that were started by Kubernetes..." + printf "${yellow}Stopping and removing all other containers that were started by Kubernetes...${reset}\n" docker stop $k8s_containers docker rm -f -v $k8s_containers fi + +cd ../scripts +if [ -n "$start_registry" ]; then + ./start-docker-registry.sh stop +fi + diff --git a/kube-up.sh b/kube-up.sh index da2222b..088962e 100755 --- a/kube-up.sh +++ b/kube-up.sh @@ -1,7 +1,57 @@ #!/bin/bash +source ./common.sh + +# CLI arguments +port_forward=1 +add_route=1 +start_dns=1 +start_ui=1 +start_registry=0 +silent=0 + +read -r -d '' HELP_TEXT <<'USAGE_TEXT' +Usage: kube-up.sh [-fndursh] +Available options are: + -f disable forward to port 8080 on docker machine (required for kubectl) + -n disable adding route to enable local name resolution via skyDNS + -d disable skyDNS + -u disable kube-ui + -r start local docker registry + -s silent mode + -h show this help text +USAGE_TEXT + +function show_help { + echo "$HELP_TEXT" + exit 0 +} + +while getopts "fndushr?:" opt; do + case "$opt" in + h|\?) + show_help + exit 0 + ;; + f) port_forward=0 + ;; + n) add_route=0 + ;; + d) start_dns=0 + ;; + u) start_ui=0 + ;; + r) start_registry=1 + ;; + s) silent=1 + ;; + esac +done + +#echo "port_forward='$port_forward', add_route='$add_route', start_dns: '$start_dns'" + require_command_exists() { - command -v "$1" >/dev/null 2>&1 || { echo "$1 is required but is not installed. Aborting." >&2; exit 1; } + command -v "$1" >/dev/null 2>&1 || { printf "${red}$1 is required but is not installed. Aborting.\n${reset}" >&2; exit 1; } } require_command_exists kubectl @@ -10,19 +60,37 @@ require_command_exists docker-compose docker info > /dev/null if [ $? != 0 ]; then - echo "A running Docker engine is required. Is your Docker host up?" + printf "${red}A running Docker engine is required. Is your Docker host up?${reset}\n" exit 1 fi +printf "${yellow}Composing k8s cluster...${reset}\n" cd kubernetes docker-compose up -d cd ../scripts +echo + if [ $(command -v docker-machine) ] && [ ! -z "$(docker-machine active)" ]; then - ./docker-machine-port-forwarding.sh + if [ "$port_forward" -eq 1 ]; then + ./docker-machine-port-forwarding.sh + fi + if [ "$add_route" -eq 1 ]; then + ./docker-machine-add-route.sh + fi fi ./wait-for-kubernetes.sh -./activate-dns.sh -./activate-kube-ui.sh + +if [ "$start_dns" -eq 1 ]; then + ./activate-dns.sh +fi + +if [ "$start_ui" -eq 1 ]; then + ./activate-kube-ui.sh +fi + +if [ "$start_registry" -eq 1 ]; then + ./start-docker-registry.sh start +fi diff --git a/kubernetes/docker-compose.yml b/kubernetes/docker-compose.yml index 77232a2..a1c3b7d 100644 --- a/kubernetes/docker-compose.yml +++ b/kubernetes/docker-compose.yml @@ -25,9 +25,9 @@ proxy: kube2sky: image: gcr.io/google_containers/kube2sky:1.11 net: host - command: ['--kube_master_url=http://127.0.0.1:8080', '--domain=cluster.local'] + command: ['--kube_master_url=http://127.0.0.1:8080', '--domain=cluster.local', '--v=2'] skydns: image: gcr.io/google_containers/skydns:2015-03-11-001 net: host - command: ['--machines=http://localhost:4001', '--addr=0.0.0.0:53', '--domain=cluster.local'] + command: ['--machines=http://localhost:4001', '--addr=0.0.0.0:53', '--domain=cluster.local', '-nameservers=8.8.8.8:53,8.8.4.4:53'] diff --git a/scripts/activate-dns.sh b/scripts/activate-dns.sh index 6632224..a5f3113 100755 --- a/scripts/activate-dns.sh +++ b/scripts/activate-dns.sh @@ -1,8 +1,19 @@ #!/bin/bash +source ../common.sh + dns_host=$(echo $DOCKER_HOST | awk -F'[/:]' '{print $4}') -kubectl --namespace=kube-system create -f - << EOF +printf "${yellow}Activating DNS...${reset}\n" + +dns_cluster_ip=$(kubectl get services --namespace=kube-system kube-dns --template={{.spec.clusterIP}} 2> /dev/null) + +if [ -n "$dns_cluster_ip" ]; then + printf "\n${yellow} ${warning} Kube DNS service already exists. ClusterIP: $dns_cluster_ip${reset}\n\n" + exit 0; +fi + +kubectl --namespace=kube-system create -f - << EOF > /dev/null apiVersion: v1 kind: Endpoints metadata: @@ -17,7 +28,7 @@ subsets: name: dns EOF -kubectl --namespace=kube-system create -f - << EOF +kubectl --namespace=kube-system create -f - << EOF > /dev/null kind: Service apiVersion: v1 metadata: @@ -30,3 +41,5 @@ spec: port: 53 protocol: UDP EOF + +check_rc "Successfully started kube-dns" "Could not start kube-dns" diff --git a/scripts/activate-kube-ui.sh b/scripts/activate-kube-ui.sh index 45e93e8..6131994 100755 --- a/scripts/activate-kube-ui.sh +++ b/scripts/activate-kube-ui.sh @@ -1,32 +1,41 @@ #!/bin/bash -echo "Activating Kube UI..." +source ../common.sh -kubectl --namespace=kube-system create -f - << EOF +printf "${yellow}Activating Kube UI...${reset}\n" + +kube_ui_cluster_ip=$(kubectl get services --namespace=kube-system kube-ui --template={{.spec.clusterIP}} 2> /dev/null) + +if [ -n "$kube_ui_cluster_ip" ]; then + printf "\n${yellow} ${warning} Kube-UI service already exists. ClusterIP: $kube_ui_cluster_ip${reset}\n\n" + exit 0 +fi + +kubectl --namespace=kube-system create -f - << EOF > /dev/null apiVersion: v1 kind: ReplicationController metadata: - name: kube-ui-v2 + name: kube-ui-v3 namespace: kube-system labels: k8s-app: kube-ui - version: v2 + version: v3 kubernetes.io/cluster-service: "true" spec: replicas: 1 selector: k8s-app: kube-ui - version: v2 + version: v3 template: metadata: labels: k8s-app: kube-ui - version: v2 + version: v3 kubernetes.io/cluster-service: "true" spec: containers: - name: kube-ui - image: gcr.io/google_containers/kube-ui:v2 + image: gcr.io/google_containers/kube-ui:v3 resources: limits: cpu: 100m @@ -41,7 +50,7 @@ spec: timeoutSeconds: 5 EOF -kubectl --namespace=kube-system create -f - << EOF +kubectl --namespace=kube-system create -f - << EOF > /dev/null apiVersion: v1 kind: Service metadata: @@ -58,3 +67,5 @@ spec: - port: 80 targetPort: 8080 EOF + +check_rc "Successfully started kube-ui" "Could not start kube-ui" diff --git a/scripts/docker-machine-add-route.sh b/scripts/docker-machine-add-route.sh new file mode 100755 index 0000000..53efd4c --- /dev/null +++ b/scripts/docker-machine-add-route.sh @@ -0,0 +1,42 @@ +#!/bin/bash +# +# Set up routes for accessing services and DNS from MacOS +source ../common.sh + +machine=$(docker-machine active) +docker_net=${DOCKER_MACHINE_NET:=10.0.0.0/16} + +rx='([1-9]?[0-9]|1[0-9]{2}|2[0-4][0-9]|25[0-5])' + +function add_route { + machine_name=$1 + docker_network=$2 + docker_machine_ip=$(docker-machine ip $machine_name) + if [ $? -ne 0 ]; then + exit -1; + fi + + printf "${yellow}Checking routing entries for ${docker_net}...${reset}\n" + + if [[ $docker_machine_ip =~ ^$rx\.$rx\.$rx\.$rx$ ]]; then + default_gateway=$(route -n get default | grep gateway | awk '{print $2}') + existing_route_gateway=$(route -n get $docker_network | grep gateway | awk '{print $2}') + if [ -z "$existing_route_gateway" ] || [ "$existing_route_gateway" == "$default_gateway" ]; then + printf "${yellow}Adding route for docker-machine '$machine_name' and IP '$docker_machine_ip' requires sudo, please enter password${reset}\n" + sudo route -n add $docker_network $docker_machine_ip + if [ $? -eq 0 ]; then + printf "\n${green} ${checkmark} Successfully added route '$docker_net' -> '${docker_machine_ip}' ${reset}\n\n" + else + printf "\n${error} ${error} Cannot add route\n\n" + fi + elif [ "$existing_route_gateway" == "$docker_machine_ip" ]; then + printf "\n${yellow} ${warning} Route entry already exists\n\n${reset}" + else + printf "\n${red} ${error} Existing route for $docker_network: $existing_route_gateway\n\n${reset}" + fi + else + printf "\n${red} ${error} No valid IP address for docker machine $machine_name: $docker_machine_ip\n\n${reset}" + fi +} + +add_route $machine $docker_net diff --git a/scripts/docker-machine-port-forwarding.sh b/scripts/docker-machine-port-forwarding.sh index 3c43fa9..67e5da3 100755 --- a/scripts/docker-machine-port-forwarding.sh +++ b/scripts/docker-machine-port-forwarding.sh @@ -2,13 +2,24 @@ # # Set up kubectl port forwarding to boot2docker VM if needed. +source ../common.sh + function forward_port_if_not_forwarded { port=$1 - forward_port_command="ssh -f -N -L $port:localhost:$port docker@$(docker-machine ip $(docker-machine active))" + + machine=$(docker-machine active) + keyfile="$HOME/.docker/machine/machines/$machine/id_rsa" + + printf "${yellow}Checking forward for port '$port'${reset}\n" + forward_port_command="ssh -i $keyfile -f -N -L $port:localhost:$port docker@$(docker-machine ip $machine)" existing_forward=$(ps ax | grep "$forward_port_command" | grep -v grep) - + if [ -z "$existing_forward" ]; then - eval $forward_port_command + #printf "${yellow}Adding portforward for port '$port'${reset}\n" + eval $forward_port_command &> /dev/null + check_rc "Successfully added port forward" "Could not forward port" + else + printf "\n${yellow} ${warning} Port forward for '$port' already exists${reset}\n\n" fi } diff --git a/scripts/start-docker-registry.sh b/scripts/start-docker-registry.sh new file mode 100755 index 0000000..6332693 --- /dev/null +++ b/scripts/start-docker-registry.sh @@ -0,0 +1,59 @@ +#!/bin/bash +# +# starts a local Docker registry that can be used to make local images available to k8s + +source ../common.sh + +function start_docker_registry { + action=$1 + run_new_registry_cmd="docker run -d -p 5000:5000 --restart=always --name registry registry:2" + if [ $? -ne 0 ]; then + printf "\n${red} ${error}docker command failed. Make sure that docker is running and shell environment is sane${reset}\n" + exit -1 + fi + + existing_registry=$(docker ps -a | grep registry:2 | awk '{print $1}') + run_existing_registry_cmd="docker start $existing_registry" + running_registry=$(docker ps | grep registry:2 | awk '{print $1}') + stop_registry_cmd="docker stop $running_registry" + case "$action" in + "start") + printf "${yellow}Starting docker registry...${reset}\n" + if [ -z "$running_registry" ]; then + if [ -z "$existing_registry" ]; then + eval $run_new_registry_command &> /dev/null + else + #printf "${yellow}Using existing container: $existing_registry${reset}\n" + eval $run_existing_registry_cmd &> /dev/null + fi + + check_rc "Docker registry started" "Docker registry startup failed" + + else + printf "\n${yellow} ${warning} Docker registry already running. Container ID: $running_registry${reset}\n\n" + fi + ;; + "stop") + if [ -z "$running_registry" ]; then + printf "\n${yellow} ${warning} Docker registry not running.${reset}\n\n" + else + printf "${yellow}Shutting down docker registry. Container ID: $running_registry${reset}\n" + eval $stop_registry_cmd &> /dev/null + + check_rc "Docker registry stopped" "Docker registry shutdown failed" + fi + ;; + "check") + if [ -n "$running_registry" ]; then + echo "Docker registry already running. Container ID: $running_registry" + elif [ -n "$existing_registry" ]; then + echo "Docker registry NOT running but container exists: $existing_registry" + fi + ;; + *) + echo "Usage: docker_registry start|stop|check" + ;; + esac +} + +start_docker_registry $1 diff --git a/scripts/wait-for-kubernetes.sh b/scripts/wait-for-kubernetes.sh index 68c0207..c273e04 100755 --- a/scripts/wait-for-kubernetes.sh +++ b/scripts/wait-for-kubernetes.sh @@ -1,8 +1,11 @@ #!/bin/bash -echo "Waiting for Kubernetes cluster to become available..." +source ../common.sh + +printf "${yellow}Waiting for Kubernetes cluster to become available${reset}" until $(kubectl cluster-info &> /dev/null); do sleep 1 + printf "${yellow}.${reset}" done -echo "Kubernetes cluster is up." +printf "\n\n${green} ${checkmark} Kubernetes cluster is up.${reset}\n\n"