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

Update update-demo example to use kubectl #3576

Merged
merged 2 commits into from
Jan 28, 2015
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Jump to
Jump to file
Failed to load files.
Diff view
Diff view
4 changes: 4 additions & 0 deletions examples/examples_test.go
Original file line number Diff line number Diff line change
Expand Up @@ -123,6 +123,10 @@ func TestExampleObjectSchemas(t *testing.T) {
"service": &api.Service{},
"replication-controller": &api.ReplicationController{},
},
"../examples/update-demo": {
"kitten-rc": &api.ReplicationController{},
"nautilus-rc": &api.ReplicationController{},
},
}

for path, expected := range cases {
Expand Down
5 changes: 4 additions & 1 deletion examples/update-demo/1-run-web-proxy.sh
Original file line number Diff line number Diff line change
Expand Up @@ -24,6 +24,9 @@ echo
echo " http://localhost:8001/static/"
echo

export KUBE_ROOT=$(dirname $0)/../..
export KUBECTL=${KUBE_REPO_ROOT}/cluster/kubectl.sh

set -x

../../cluster/kubecfg.sh -proxy -www local/
$KUBECTL proxy --www=local/
8 changes: 5 additions & 3 deletions examples/update-demo/2-create-replication-controller.sh
Original file line number Diff line number Diff line change
Expand Up @@ -23,9 +23,11 @@ if [[ "${DOCKER_HUB_USER+set}" != "set" ]] ; then
exit 1
fi

export KUBE_REPO_ROOT=${KUBE_REPO_ROOT-$(dirname $0)/../..}
export KUBECFG=${KUBECFG-$KUBE_REPO_ROOT/cluster/kubecfg.sh}
export KUBE_ROOT=$(dirname $0)/../..
export KUBECTL=${KUBE_REPO_ROOT}/cluster/kubectl.sh

set -x

$KUBECFG -p 8080:80 run $DOCKER_HUB_USER/update-demo:nautilus 2 update-demo
SCHEMA=${KUBE_REPO_ROOT}/examples/update-demo/nautilus-rc.yaml

cat ${SCHEMA} | sed "s/DOCKER_HUB_USER/${DOCKER_HUB_USER}/" | ${KUBECTL} create -f -
4 changes: 2 additions & 2 deletions examples/update-demo/3-scale.sh
Original file line number Diff line number Diff line change
Expand Up @@ -21,8 +21,8 @@ set -o pipefail
NEW_SIZE=${1:-4}

export KUBE_REPO_ROOT=${KUBE_REPO_ROOT-$(dirname $0)/../..}
export KUBECFG=${KUBECFG-$KUBE_REPO_ROOT/cluster/kubecfg.sh}
export KUBECTL=${KUBECTL-$KUBE_REPO_ROOT/cluster/kubectl.sh}

set -x
Copy link
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Maybe a silly question: why leave set -x here but remove it elsewhere?

Copy link
Contributor Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

I initially thought the sed command showing up in output was messy, but set -x output is one command per line, so it's fine. Put it back elsewhere.

Copy link
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

An optional nit would be to be consistent about where it's set, i.e. before/after export groups. But this is getting into minutia.


$KUBECFG resize update-demo $NEW_SIZE
$KUBECTL resize rc update-demo-nautilus --replicas=$NEW_SIZE
12 changes: 7 additions & 5 deletions examples/update-demo/4-rolling-update.sh
Original file line number Diff line number Diff line change
Expand Up @@ -23,11 +23,13 @@ if [[ "${DOCKER_HUB_USER+set}" != "set" ]] ; then
exit 1
fi

NEW_IMAGE=${1:-kitten}
TIMING=${2:-10s}
export KUBE_REPO_ROOT=${KUBE_REPO_ROOT-$(dirname $0)/../..}
export KUBECFG=${KUBECFG-$KUBE_REPO_ROOT/cluster/kubecfg.sh}
export KUBE_ROOT=$(dirname $0)/../..
export KUBECTL=${KUBE_ROOT}/cluster/kubectl.sh

set -x

$KUBECFG -image $DOCKER_HUB_USER/update-demo:$NEW_IMAGE -u $TIMING rollingupdate update-demo
NEW_IMAGE=${1:-kitten}
TIMING=${2:-10s}
SCHEMA=${KUBE_ROOT}/examples/update-demo/kitten-rc.yaml

cat ${SCHEMA} | sed "s/DOCKER_HUB_USER/${DOCKER_HUB_USER}/" | ${KUBECTL} rollingupdate update-demo-nautilus -f - --update-period=10s
9 changes: 5 additions & 4 deletions examples/update-demo/5-down.sh
Original file line number Diff line number Diff line change
Expand Up @@ -18,10 +18,11 @@ set -o errexit
set -o nounset
set -o pipefail

export KUBE_REPO_ROOT=${KUBE_REPO_ROOT-$(dirname $0)/../..}
export KUBECFG=${KUBECFG-$KUBE_REPO_ROOT/cluster/kubecfg.sh}
export KUBE_ROOT=$(dirname $0)/../..
export KUBECTL=${KUBE_ROOT}/cluster/kubectl.sh

set -x

$KUBECFG stop update-demo
$KUBECFG rm update-demo
rc="update-demo-kitten"

$KUBECTL stop rc ${rc}
12 changes: 6 additions & 6 deletions examples/update-demo/README.md
Original file line number Diff line number Diff line change
Expand Up @@ -61,8 +61,8 @@ separate terminal or run it in the background.

http://localhost:8001/static/

+ ../../cluster/kubecfg.sh -proxy -www local/
I0922 11:43:54.886018 15659 kubecfg.go:209] Starting to serve on localhost:8001
+ ../../cluster/kubectl.sh proxy --www=local/
I0115 16:50:15.959551 19790 proxy.go:34] Starting to serve on localhost:8001
```

Now visit the the [demo website](http://localhost:8001/static). You won't see anything much quite yet.
Expand Down Expand Up @@ -92,12 +92,12 @@ We will now update the docker image to serve a different image by doing a rollin
```bash
$ ./4-rolling-update.sh
```
The rollingUpdate command in kubecfg will do 2 things:
The rollingUpdate command in kubectl will do 2 things:

1. Update the template in the replication controller to the new image (`$DOCKER_HUB_USER/update-demo:kitten`)
2. Kill each of the pods one by one. It'll let the replication controller create new pods to replace those that were killed.
1. Create a new replication controller with a pod template that uses the new image (`$DOCKER_HUB_USER/update-demo:kitten`)
2. Resize the old and new replication controllers until the new controller replaces the old. This will kill the current pods one at a time, spinnning up new ones to replace them.

Watch the UX, it will update one pod every 10 seconds until all of the pods have the new image.
Watch the [demo website](http://localhost:8001/static/index.html), it will update one pod every 10 seconds until all of the pods have the new image.

### Step Five: Bring down the pods

Expand Down
20 changes: 20 additions & 0 deletions examples/update-demo/kitten-rc.yaml
Original file line number Diff line number Diff line change
@@ -0,0 +1,20 @@
kind: ReplicationController
id: update-demo-kitten
Copy link
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Since you're running this through sed anyway, why not parameterize kitten vs. nautilus (e.g., IMAGE_VERSION)?

Really we should be using jinja, jq, or something, but sed will work and doesn't create additional package dependencies.

Copy link
Contributor Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

I want a separate schema for the replacement controller, so it can omit #replicas and inherit #replicas from the running controller. Doesn't seem to be a benefit to further parameterizing unless we are merging the 2 schemas.

Copy link
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Oh, right. Missed that. Ok.

apiVersion: v1beta1
desiredState:
replicaSelector:
name: update-demo
version: kitten
podTemplate:
desiredState:
manifest:
containers:
- name: update-demo
image: DOCKER_HUB_USER/update-demo:kitten
ports:
- hostPort: 8080
Copy link
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

ditto hostPort question

containerPort: 80
protocol: TCP
labels:
name: update-demo
version: kitten
14 changes: 11 additions & 3 deletions examples/update-demo/local/script.js
Original file line number Diff line number Diff line change
Expand Up @@ -46,7 +46,7 @@ var updateServer = function($http, server) {
};

var updateData = function($scope, $http) {
var servers = $scope.servers
var servers = $scope.servers;
for (var i = 0; i < servers.length; ++i) {
var server = servers[i];
updateServer($http, server);
Expand All @@ -69,6 +69,10 @@ var getServer = function($scope, id) {
return null;
};

var isUpdateDemoPod = function(pod) {
return pod.labels && pod.labels.name == "update-demo";
};

var update = function($scope, $http) {
if (!$http) {
console.log("No HTTP!");
Expand All @@ -79,9 +83,13 @@ var update = function($scope, $http) {
console.log(data);
var newServers = [];
for (var i = 0; i < data.items.length; ++i) {
var server = getServer($scope, data.items[i].id);
var pod = data.items[i];
if (!isUpdateDemoPod(pod)) {
continue;
}
var server = getServer($scope, pod.id);
if (server == null) {
server = { "id": data.items[i].id };
server = { "id": pod.id };
}
newServers.push(server);
}
Expand Down
21 changes: 21 additions & 0 deletions examples/update-demo/nautilus-rc.yaml
Original file line number Diff line number Diff line change
@@ -0,0 +1,21 @@
kind: ReplicationController
id: update-demo-nautilus
apiVersion: v1beta1
desiredState:
replicas: 2
replicaSelector:
name: update-demo
version: nautilus
podTemplate:
desiredState:
manifest:
containers:
- name: update-demo
image: DOCKER_HUB_USER/update-demo:nautilus
ports:
- hostPort: 8080
Copy link
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

@roberthbailey mentioned in another example we shouldn't be using hostPort any longer. Does this apply here?

Copy link
Contributor Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

I think hostPort is fine for examples. It's easy to understand and setup firewall rules for, and keeps this example simple (just creates rc, no need to also create a service with external loadbalancer).

containerPort: 80
protocol: TCP
labels:
name: update-demo
version: nautilus
16 changes: 8 additions & 8 deletions hack/e2e-suite/update.sh
Original file line number Diff line number Diff line change
Expand Up @@ -38,7 +38,7 @@ function validate() {
sleep 2

local pod_id_list
pod_id_list=($($KUBECFG -template='{{range.items}}{{.id}} {{end}}' -l name="${CONTROLLER_NAME}" list pods))
pod_id_list=($($KUBECTL get pods -o template --template='{{range.items}}{{.id}} {{end}}' -l name="${CONTROLLER_NAME}"))

echo " ${#pod_id_list[@]} out of ${num_replicas} created"

Expand All @@ -54,19 +54,19 @@ function validate() {
# NB: kubectl & kubecfg add the "exists" function to the standard template functions.
# This lets us check to see if the "running" entry exists for each of the containers
# we care about. Exists will never return an error and it's safe to check a chain of
# things, any one of which may not exist. In the below template, all of info,
# things, any one of which may not exist. In the below template, all of info,
# containername, and running might be nil, so the normal index function isn't very
# helpful.
# This template is unit-tested in kubec{tl|fg}, so if you change it, update the unit test.
#
# You can read about the syntax here: http://golang.org/pkg/text/template/
template_string="{{and (exists . \"currentState\" \"info\" \"${CONTROLLER_NAME}\" \"state\" \"running\") (exists . \"currentState\" \"info\" \"POD\" \"state\" \"running\")}}"
current_status=$($KUBECFG -template="${template_string}" get "pods/$id") || {
template_string="{{and (exists . \"currentState\" \"info\" \"${CONTROLLER_NAME}\" \"state\" \"running\") (exists . \"currentState\" \"info\" \"net\" \"state\" \"running\")}}"
current_status=$($KUBECTL get pods "$id" -o template --template="${template_string}") || {
if [[ $current_status =~ "pod \"${id}\" not found" ]]; then
echo " $id no longer exists"
continue
else
echo " kubecfg failed with error:"
echo " kubectl failed with error:"
echo $current_status
exit -1
fi
Expand All @@ -79,14 +79,14 @@ function validate() {
echo " $id is created and both POD and update-demo containers are running: $current_status"

template_string="{{(index .currentState.info \"${CONTROLLER_NAME}\").image}}"
current_image=$($KUBECFG -template="${template_string}" get "pods/$id") || true
current_image=$($KUBECTL get pods "$id" -o template --template="${template_string}") || true
if [[ "$current_image" != "${DOCKER_HUB_USER}/update-demo:${container_image_version}" ]]; then
echo " ${id} is created but running wrong image"
continue
fi


host_ip=$($KUBECFG -template='{{.currentState.hostIP}}' get pods/$id)
host_ip=$($KUBECTL get pods "$id" -o template --template='{{.currentState.hostIP}}')
curl -s --max-time 5 --fail http://${host_ip}:8080/data.json \
| grep -q ${container_image_version} || {
echo " ${id} is running the right image but curl to contents failed or returned wrong info"
Expand All @@ -102,7 +102,7 @@ function validate() {
return 0
}

export DOCKER_HUB_USER=davidopp
export DOCKER_HUB_USER=jlowdermilk

# Launch a container
${KUBE_ROOT}/examples/update-demo/2-create-replication-controller.sh
Expand Down
4 changes: 2 additions & 2 deletions pkg/kubectl/cmd/proxy.go
Original file line number Diff line number Diff line change
Expand Up @@ -36,9 +36,9 @@ func (f *Factory) NewCmdProxy(out io.Writer) *cobra.Command {
clientConfig, err := f.ClientConfig(cmd)
checkErr(err)

server, err := kubectl.NewProxyServer(GetFlagString(cmd, "www"), clientConfig, port)
server, err := kubectl.NewProxyServer(GetFlagString(cmd, "www"), clientConfig)
checkErr(err)
glog.Fatal(server.Serve())
glog.Fatal(server.Serve(port))
},
}
cmd.Flags().StringP("www", "w", "", "Also serve static files from the given directory under the prefix /static")
Expand Down
9 changes: 4 additions & 5 deletions pkg/kubectl/proxy_server.go
Original file line number Diff line number Diff line change
Expand Up @@ -29,12 +29,11 @@ import (
// ProxyServer is a http.Handler which proxies Kubernetes APIs to remote API server.
type ProxyServer struct {
httputil.ReverseProxy
Port int
}

// NewProxyServer creates and installs a new ProxyServer.
// It automatically registers the created ProxyServer to http.DefaultServeMux.
func NewProxyServer(filebase string, cfg *client.Config, port int) (*ProxyServer, error) {
func NewProxyServer(filebase string, cfg *client.Config) (*ProxyServer, error) {
prefix := cfg.Prefix
if prefix == "" {
prefix = "/api"
Expand All @@ -52,9 +51,9 @@ func NewProxyServer(filebase string, cfg *client.Config, port int) (*ProxyServer
return proxy, nil
}

// Serve starts the server (http.DefaultServeMux) on TCP port 8001, loops forever.
func (s *ProxyServer) Serve() error {
addr := fmt.Sprintf(":%d", s.Port)
// Serve starts the server (http.DefaultServeMux) on given port, loops forever.
func (s *ProxyServer) Serve(port int) error {
addr := fmt.Sprintf(":%d", port)
return http.ListenAndServe(addr, nil)
}

Expand Down