Skip to content

Commit f12945a

Browse files
authored
Merge pull request agones-dev#48 from googleprivate/feature/minikube
Development and Deployment to Minikube
2 parents 4a1a5da + 8388c84 commit f12945a

7 files changed

Lines changed: 247 additions & 47 deletions

File tree

build/Makefile

Lines changed: 82 additions & 9 deletions
Original file line numberDiff line numberDiff line change
@@ -36,9 +36,11 @@ VERSION ?= $(base_version)-$(shell git rev-parse --short HEAD)
3636
# The registry that is being used to store docker images
3737
REGISTRY ?= gcr.io/agon-images
3838
# Where the kubectl configuration files are being stored
39-
KUBECONFIG ?= $(build_path)/.kube
39+
KUBEPATH ?= ~/.kube
4040
# The (gcloud) test cluster that is being worked against
4141
CLUSTER_NAME ?= test-cluster
42+
# the profile to use when developing on minikube
43+
MINIKUBE_PROFILE ?= agon
4244

4345
# Directory that this Makefile is in.
4446
mkfile_path := $(abspath $(lastword $(MAKEFILE_LIST)))
@@ -48,7 +50,7 @@ agon_path := $(realpath $(build_path)/..)
4850
agon_package = github.com/agonio/agon
4951
mount_path = /go/src/$(agon_package)
5052
common_mounts = -v $(build_path)/.config/gcloud:/root/.config/gcloud \
51-
-v $(KUBECONFIG):/root/.kube \
53+
-v $(KUBEPATH):/root/.kube \
5254
-v $(agon_path):$(mount_path)
5355

5456
# Use a hash of the Dockerfile for the tag, so when the Dockerfile changes,
@@ -84,11 +86,15 @@ test: ensure-build-image
8486
# Push all the images up to $(REGISTRY)
8587
push: push-gameservers-controller-image push-gameservers-sidecar-image
8688

87-
# install the development version of Agon
89+
# Installs the current development version of Agon into the Kubernetes cluster
90+
install: ALWAYS_PULL_SIDECAR := true
91+
install: IMAGE_PULL_POLICY := "Always"
8892
install:
8993
cp $(build_path)/install.yaml $(build_path)/.install.yaml
90-
sed -i -e 's!$${REGISTRY}!$(REGISTRY)!g' -e 's!$${VERSION}!$(VERSION)!g' $(build_path)/.install.yaml
91-
docker run --rm $(common_mounts) --entrypoint=kubectl $(build_tag) apply -f $(mount_path)/build/.install.yaml
94+
sed -i -e 's!$${REGISTRY}!$(REGISTRY)!g' -e 's!$${VERSION}!$(VERSION)!g' \
95+
-e 's!$${IMAGE_PULL_POLICY}!$(IMAGE_PULL_POLICY)!g' -e 's!$${ALWAYS_PULL_SIDECAR}!$(ALWAYS_PULL_SIDECAR)!g' \
96+
$(build_path)/.install.yaml
97+
docker run --rm $(common_mounts) $(ARGS) $(build_tag) kubectl apply -f $(mount_path)/build/.install.yaml
9298

9399
# Build a static binary for the gameserver controller
94100
build-gameservers-controller-binary: ensure-build-image
@@ -182,6 +188,13 @@ push-build-image:
182188
docker tag $(build_tag) $(build_remote_tag)
183189
docker push $(build_remote_tag)
184190

191+
# ____ _ ____ _ _
192+
# / ___| ___ ___ __ _| | ___ / ___| | ___ _ _ __| |
193+
# | | _ / _ \ / _ \ / _` | |/ _ \ | | | |/ _ \| | | |/ _` |
194+
# | |_| | (_) | (_) | (_| | | __/ | |___| | (_) | |_| | (_| |
195+
# \____|\___/ \___/ \__, |_|\___| \____|_|\___/ \__,_|\__,_|
196+
# |___/
197+
185198
# Initialise the gcloud login and project configuration, if you are working with GCP
186199
gcloud-init: ensure-build-config
187200
docker run --rm -it \
@@ -213,7 +226,67 @@ gcloud-auth-docker: ensure-build-image
213226
sudo mv /tmp/gcloud-auth-docker/.dockercfg ~/
214227
sudo chown $(USER) ~/.dockercfg
215228

216-
# Clean the kubernetes and gcloud configuration
217-
clean-config:
218-
-sudo rm -r $(build_path)/.kube
219-
-sudo rm -r $(build_path)/.config
229+
# Clean the gcloud configuration
230+
clean-gcloud-config:
231+
-sudo rm -r $(build_path)/.config
232+
233+
# __ __ _ _ _ _
234+
# | \/ (_)_ __ (_) | ___ _| |__ ___
235+
# | |\/| | | '_ \| | |/ / | | | '_ \ / _ \
236+
# | | | | | | | | | <| |_| | |_) | __/
237+
# |_| |_|_|_| |_|_|_|\_\\__,_|_.__/ \___|
238+
#
239+
240+
# Switches to an agon profile, and starts a kubernetes cluster
241+
# of the right version. Also mounts the project directory into minikube,
242+
# so that the build tools will work.
243+
#
244+
# Use DRIVER variable to change the VM driver (default virtualbox) if you so desire.
245+
minikube-test-cluster: DRIVER := virtualbox
246+
minikube-test-cluster: minikube-agon-profile
247+
minikube start --kubernetes-version v1.8.0 --vm-driver $(DRIVER)
248+
$(MAKE) minikube-ensure-build-image
249+
minikube mount $(agon_path):$(agon_path)
250+
251+
# switch to the agon cluster
252+
minikube-agon-profile:
253+
minikube profile $(MINIKUBE_PROFILE)
254+
255+
# Connecting to minikube requires so enhanced permissions, so use this target
256+
# instead of `make shell` to start an interactive shell for development on minikube.
257+
minikube-shell: ensure-build-image
258+
eval $$(minikube docker-env --unset) && \
259+
$(MAKE) shell ARGS="--network=host -v ~/.minikube:$(HOME)/.minikube"
260+
261+
# Convenience target to build Agon's docker images directly on minikube.
262+
minikube-build: minikube-ensure-build-image
263+
eval $$(minikube docker-env) && \
264+
$(MAKE) build-images
265+
266+
# ensure minikube has the build image, if not, grab it
267+
minikube-ensure-build-image: ensure-build-image
268+
@if [ -z $$(minikube ssh -- docker images -q $(build_tag)) ]; then\
269+
echo "Could not find $(build_tag) image. Transferring...";\
270+
$(MAKE) minikube-transfer TAG=$(build_tag);\
271+
fi
272+
273+
# Instead of building Agon's docker images inside minikube,
274+
# use this command to push the local images that have already been built
275+
# via `make build` or `make build-images`.
276+
#
277+
# Depending on the virtualisation driver/configuration,
278+
# it may be faster to build locally and push, rather than building directly on minikube.
279+
minikube-push:
280+
$(MAKE) minikube-transfer TAG=$(sidecar_tag)
281+
$(MAKE) minikube-transfer TAG=$(controller_tag)
282+
283+
# Installs the current development version of Agon into the Kubernetes cluster.
284+
# Use this instead of `make install`, as it disables PullAlways on the install.yaml
285+
minikube-install: ensure-build-image
286+
eval $$(minikube docker-env --unset) && \
287+
$(MAKE) install ARGS="--network=host -v ~/.minikube:/$(HOME)/.minikube" ALWAYS_PULL_SIDECAR=false IMAGE_PULL_POLICY=IfNotPresent
288+
289+
# convenience target for transferring images into minikube
290+
minikube-transfer:
291+
eval $$(minikube docker-env --unset) && \
292+
docker save $(TAG) | (eval $$(minikube docker-env) && docker load)

build/README.md

Lines changed: 102 additions & 10 deletions
Original file line numberDiff line numberDiff line change
@@ -7,6 +7,10 @@ Rather than installing all the dependencies locally, you can test and build Agon
77
built from the Dockerfile in this directory. There is an accompanying Makefile for all the common
88
tasks you may wish to accomplish.
99

10+
**Note** - this has been tested on Linux. Tickets for [OSX](https://github.com/googleprivate/agon/issues/46)
11+
and [Windows](https://github.com/googleprivate/agon/issues/47) exist, and require work. Testing on these platforms
12+
and reporting bugs is appreciated.
13+
1014
<!-- ToC start -->
1115
## Table of Contents
1216

@@ -18,12 +22,13 @@ tasks you may wish to accomplish.
1822
1. [Make Variable Reference](#make-variable-reference)
1923
1. [VERSION](#version)
2024
1. [REGISTRY](#registry)
21-
1. [KUBECONFIG](#kubeconfig)
25+
1. [KUBEPATH](#kubepath)
2226
1. [CLUSTER_NAME](#cluster_name)
2327
1. [Make Target Reference](#make-target-reference)
2428
1. [Development Targets](#development-targets)
2529
1. [Build Image Targets](#build-image-targets)
2630
1. [Google Cloud Platform](#google-cloud-platform)
31+
1. [Minikube](#minikube)
2732
<!-- ToC end -->
2833

2934
## GOPATH
@@ -69,8 +74,8 @@ to be open to UDP traffic.
6974

7075
First step is to create a Google Cloud Project at https://console.cloud.google.com or reuse an existing one.
7176

72-
The build tools (by default) maintain configuration for gcloud and kubectl within the `build` folder, so as to keep
73-
everything seperate (see below for overwriting these config locations). Therefore, once the project has been created,
77+
The build tools (by default) maintain configuration for gcloud within the `build` folder, so as to keep
78+
everything separate (see below for overwriting these config locations). Therefore, once the project has been created,
7479
we will need to authenticate out gcloud tooling against it. To do that run `make gcloud-init` and fill in the
7580
prompts as directed.
7681

@@ -81,8 +86,8 @@ done you can go to the Google Cloud Platform console and see that a cluster is u
8186
name of the test cluster you can set the `CLUSTER_NAME` environemnt varlable to value you would like.
8287

8388
To grab the kubectl authentication details for this cluster, run `make gcloud-auth-cluster`, which will generate the
84-
required Kubernetes security credintials for `kubectl`. This will be stored in `build/.kube` by default, but can also be
85-
overwritten by setting the `KUBECONFIG` environment variable before running the command.
89+
required Kubernetes security credintials for `kubectl`. This will be stored in `~/.kube` by default, but can also be
90+
overwritten by setting the `KUBEPATH` environment variable before running the command.
8691

8792
Great! Now we are setup, let's try out the development shell, and see if our `kubectl` is working!
8893

@@ -106,11 +111,60 @@ To push our images up at this point, is simple `make push` and that will push up
106111
project's container registry.
107112

108113
Now that the images are pushed, to install the development version (with all imagePolicies set to always download),
109-
run `make install` and agon will install the image that you just built and pushed on the test cluster you
114+
run `make install` and Agon will install the image that you just built and pushed on the test cluster you
110115
created at the beginning of this section. (if you want to see the resulting installation yaml, you can find it in `build/.install.yaml`)
111116

112117
### Running a Test Minikube cluster
113-
(Coming soon: Track [this bug](https://github.com/googleprivate/agon/issues/30) for details)
118+
This will setup a [Minikube](https://github.com/kubernetes/minikube) cluster, running on an `agon` profile,
119+
120+
Because Minikube runs on a virtualisation layer on the host, some of the standard build and development Make targets
121+
need to be replaced by Minikube specific targets.
122+
123+
First, [install Minikube](https://github.com/kubernetes/minikube#installation), which may also require you to install
124+
a virtualisation solution, such as [VirtualBox](https://www.virtualbox.org) as well.
125+
126+
Next we will create the Agon Minikube cluster. Run `make minikube-test-cluster` to create an `agon` profile,
127+
create a Kubernetes cluster under this profile of the supported version,
128+
and mount the development code inside the Minikube instance so we are able to build Agon inside Minikube.
129+
130+
This will also install the kubectl authentication credentials in `~/.kube`, and set the
131+
[`kubectl` context](https://kubernetes.io/docs/tasks/access-application-cluster/configure-access-multiple-clusters/)
132+
to `agon`.
133+
134+
Great! Now we are setup, let's try out the development shell, and see if our `kubectl` is working!
135+
136+
Run `make minikube-shell` to enter the development shell. You should see a bash shell that has you as the root user.
137+
Enter `kubectl get pods` and press enter. You should see that you have no resources currently, but otherwise see no errors.
138+
Assuming that all works, let's exit the shell by typing `exit` and hitting enter, and look at a couple of
139+
options for building, pushing and installing Agon next.
140+
141+
There are two options for building Agon, and depending on your virtualisation solution and its configuration
142+
each has it's pros and cons
143+
144+
#### Building directly on Minikube
145+
Since Minikube allows you to [reuse its Docker daemon](https://github.com/kubernetes/minikube/blob/master/docs/reusing_the_docker_daemon.md)
146+
we can build our images to run Agon directly on Minikube!
147+
148+
To do this, run `make minikube-build`, which will transfer the build image into the cluster
149+
and run the `build-images` target on the Minikube instance, creating the images required to run Agon.
150+
151+
Again depending on your virtualisation layer, you may want to configure it to allow it to have access to more
152+
cores and/or memory than the default, to allow for faster compilation (or for it to compile at all).
153+
154+
#### Pushing locally built images to Minikube
155+
You may remember in the first part of this walkthrough, we ran `make build`, which created all the images and binaries
156+
we needed to work with Agon locally. So instead of rebuilding them, can we push them straight into Minikube?
157+
158+
You bet we can!
159+
160+
Run `make minikube-push` which will send all of Agon's docker images from your local Docker into the Agon Minikube
161+
instance.
162+
163+
This may be better option if you find building on Minikube slow, or you just prefer to build locally.
164+
165+
Now that the images are pushed, to install the development version,
166+
run `make minikube-install` and Agon will install the images that you built and pushed to the Agon Minikube instance
167+
created at the beginning of this section. (if you want to see the resulting installation yaml, you can find it in `build/.install.yaml`)
114168

115169
### Next Steps
116170

@@ -124,8 +178,9 @@ The version of this build. Version defaults to the short hash of the latest comm
124178
### REGISTRY
125179
The registry that is being used to store docker images. Defaults to gcr.io/agon-images - the release + CI registry.
126180

127-
### KUBECONFIG
128-
Where the kubectl configuration files are being stored for shell and kubectl targets. Defaults to build/.kube
181+
### KUBEPATH
182+
The directory the kubectl configuration files are being stored for shell and kubectl targets.
183+
Defaults to ~/.kube (where your Kubernetes configs are likely to already exist)
129184

130185
### CLUSTER_NAME
131186
The (gcloud) test cluster that is being worked against. Defaults to `test-cluster`
@@ -156,6 +211,9 @@ Run all tests
156211
#### `make push`
157212
Pushes all built images up to the `$(REGISTRY)`
158213

214+
#### `make install`
215+
Installs the current development version of Agon into the Kubernetes cluster
216+
159217
#### `make shell`
160218
Run a bash shell with the developer tools (go tooling, kubectl, etc) and source code in it.
161219

@@ -189,7 +247,7 @@ Creates the build docker image
189247

190248
### Google Cloud Platform
191249

192-
A set of utilities for setting up a Container Engine cluster on Google Cloud Platform,
250+
A set of utilities for setting up a Kubernetes Engine cluster on Google Cloud Platform,
193251
since it's an easy way to get a test cluster working with Kubernetes.
194252

195253
#### `make gcloud-init`
@@ -205,3 +263,37 @@ Pulls down authentication information for kubectl against a cluster, name can be
205263
#### `make gcloud-auth-docker`
206264
Creates a short lived access to Google Cloud container repositories, so that you are able to call
207265
`docker push` directly. Useful when used in combination with `make push` command.
266+
267+
### Minikube
268+
269+
A set of utilities for setting up and running a [Minikube](https://github.com/kubernetes/minikube) instance,
270+
for local development.
271+
272+
Since Minikube runs locally, there are some targets that need to be used instead of the standard ones above.
273+
274+
#### `minikube-test-cluster`
275+
Switches to an "agon" profile, and starts a kubernetes cluster
276+
of the right version. Also mounts the project directory into Minikube,
277+
so that the build tools will work.
278+
279+
Use DRIVER variable to change the VM driver (default virtualbox) if you so desire.
280+
281+
#### `minikube-build`
282+
Convenience target to build Agon's docker images directly on Minikube.
283+
284+
#### `minikube-push`
285+
Instead of building Agon's docker images inside Minikube,
286+
use this command to push the local images that have already been built
287+
via `make build` or `make build-images`.
288+
289+
#### `minikube-install`
290+
Installs the current development version of Agon into the Kubernetes cluster.
291+
Use this instead of `make install`, as it disables PullAlways on the install.yaml
292+
293+
#### `minikube-shell`
294+
Connecting to Minikube requires so enhanced permissions, so use this target
295+
instead of `make shell` to start an interactive shell for development on Minikube.
296+
297+
Depending on the virtualisation driver/configuration,
298+
it may be faster to build locally and push, rather than building directly on Minikube.
299+

build/install.yaml

Lines changed: 2 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -45,10 +45,10 @@ spec:
4545
containers:
4646
- name: gameservers-controller
4747
image: ${REGISTRY}/gameservers-controller:${VERSION}
48-
imagePullPolicy: Always
48+
imagePullPolicy: ${IMAGE_PULL_POLICY}
4949
env:
5050
- name: ALWAYS_PULL_SIDECAR # set the sidecar imagePullPolicy to Always
51-
value: "true"
51+
value: "${ALWAYS_PULL_SIDECAR}"
5252
- name: SIDECAR # overwrite the GameServer sidecar image that is used
5353
value: ${REGISTRY}/gameservers-sidecar:${VERSION}
5454
- name: MIN_PORT

examples/cpp-simple/gameserver.yaml

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -25,4 +25,4 @@ spec:
2525
containers:
2626
- name: cpp-simple
2727
image: gcr.io/agon-images/cpp-simple-server:0.1
28-
imagePullPolicy: Always
28+
# imagePullPolicy: Always # add for development

examples/simple-udp/server/gameserver.yaml

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -25,4 +25,4 @@ spec:
2525
containers:
2626
- name: simple-udp
2727
image: gcr.io/agon-images/udp-server:0.1
28-
imagePullPolicy: Always
28+
# imagePullPolicy: Always # add for development

gameservers/controller/controller.go

Lines changed: 16 additions & 5 deletions
Original file line numberDiff line numberDiff line change
@@ -401,9 +401,9 @@ func (c *Controller) syncGameServerRequestReadyState(gs *stablev1alpha1.GameServ
401401
if err != nil {
402402
return gs, errors.Wrapf(err, "error getting pod for GameServer %s", gs.ObjectMeta.Name)
403403
}
404-
addr, err := c.externalIP(pod)
404+
addr, err := c.Address(pod)
405405
if err != nil {
406-
return gs, errors.Wrapf(err, "error getting external ip for GameServer %s", gs.ObjectMeta.Name)
406+
return gs, errors.Wrapf(err, "error getting external Address for GameServer %s", gs.ObjectMeta.Name)
407407
}
408408

409409
gsCopy := gs.DeepCopy()
@@ -479,8 +479,11 @@ func (c *Controller) listGameServerPods(gs *stablev1alpha1.GameServer) ([]*corev
479479
return result, nil
480480
}
481481

482-
// ExternalIP returns the external IP that the given Pod is being run on
483-
func (c Controller) externalIP(pod *corev1.Pod) (string, error) {
482+
// Address returns the IP that the given Pod is being run on
483+
// This should be the externalIP, but if the externalIP is
484+
// not set, it will fall back to the internalIP with a warning.
485+
// (basically because minikube only has an internalIP)
486+
func (c Controller) Address(pod *corev1.Pod) (string, error) {
484487
node, err := c.nodeLister.Get(pod.Spec.NodeName)
485488
if err != nil {
486489
return "", errors.Wrapf(err, "error retrieving node %s for Pod %s", node.ObjectMeta.Name, pod.ObjectMeta.Name)
@@ -492,7 +495,15 @@ func (c Controller) externalIP(pod *corev1.Pod) (string, error) {
492495
}
493496
}
494497

495-
return "", errors.Errorf("Could not find an external ip for Node: #%s", node.ObjectMeta.Name)
498+
// minikube only has an InternalIP on a Node, so we'll fall back to that.
499+
logrus.WithField("node", node.ObjectMeta.Name).Warn("Could not find ExternalIP. Falling back to Internal")
500+
for _, a := range node.Status.Addresses {
501+
if a.Type == corev1.NodeInternalIP {
502+
return a.Address, nil
503+
}
504+
}
505+
506+
return "", errors.Errorf("Could not find an Address for Node: %s", node.ObjectMeta.Name)
496507
}
497508

498509
// waitForEstablishedCRD blocks until CRD comes to an Established state.

0 commit comments

Comments
 (0)