I remember sitting in the audience at the first Dockercon in 2014 when Google announced Kubernetes and thinking “what kind of a name is that?”. In the intervening years, Kubernetes, or k8s for short, has battled it out with Cattle and Docker swarm and emerged as the last orchestrator standing.
I’ve been watching this happen but have been procrastinating on learning it because from a distance it looks hella complicated. Recently I decided to rip off the bandaid and set myself the challenge of getting a single container running in k8s.
While every major cloud provider is offering k8s, so far Google looks to be the easiest to get started with. So what does it take to get a container running on Google Cloud?
First some assumptions: you’ve installed the gcloud command (I used this) with the alpha commands, and you have a GCP account, and you’ve logged in with gcloud auth login
.
If you have that sorted, let’s create a project.
mike@sleepycat:~$ gcloud projects create --name projectfoo No project id provided. Use [projectfoo-208401] as project id (Y/n)? Create in progress for [https://cloudresourcemanager.googleapis.com/v1/projects/projectfoo-208401]. Waiting for [operations/cp.4790935341316997740] to finish...done.
With a project created we need to enable billing for it, so Google can charge you for the compute resources Kubernetes uses.
mike@sleepycat:~$ gcloud alpha billing projects link projectfoo-208401 --billing-account 0X0X0X-0X0X0X-0X0X0X billingAccountName: billingAccounts/0X0X0X-0X0X0X-0X0X0X billingEnabled: true name: projects/projectfoo-208401/billingInfo projectId: projectfoo-208401
Next we need to enable the Kubernetes Engine API for our new project.
mike@sleepycat:~$ gcloud services --project=projectfoo-208401 enable container.googleapis.com Waiting for async operation operations/tmo-acf.445bb50c-cf7a-4477-831c-371fea91ddf0 to complete... Operation finished successfully. The following command can describe the Operation details: gcloud services operations describe operations/tmo-acf.445bb50c-cf7a-4477-831c-371fea91ddf0
With that done, we are free to fire up a Kubernetes cluster. There is a lot going on here, more than you need, but it’s good to be able to see some of the options available. Probably the only ones to care about initially are the zone and the machine-type.
mike@sleepycat:~$ gcloud beta container --project=projectfoo-208401 clusters create "projectfoo" --zone "northamerica-northeast1-a" --username "admin" --cluster-version "1.8.10-gke.0" --machine-type "f1-micro" --image-type "COS" --disk-type "pd-standard" --disk-size "100" --scopes "https://www.googleapis.com/auth/compute","https://www.googleapis.com/auth/devstorage.read_only","https://www.googleapis.com/auth/logging.write","https://www.googleapis.com/auth/monitoring","https://www.googleapis.com/auth/servicecontrol","https://www.googleapis.com/auth/service.management.readonly","https://www.googleapis.com/auth/trace.append" --num-nodes "3" --enable-cloud-logging --enable-cloud-monitoring --addons HorizontalPodAutoscaling,HttpLoadBalancing,KubernetesDashboard --enable-autoupgrade --enable-autorepair This will enable the autorepair feature for nodes. Please see https://cloud.google.com/kubernetes-engine/docs/node-auto-repair for more information on node autorepairs. This will enable the autoupgrade feature for nodes. Please see https://cloud.google.com/kubernetes-engine/docs/node-management for more information on node autoupgrades. Creating cluster projectfoo...done. Created [https://container.googleapis.com/v1beta1/projects/projectfoo-208401/zones/northamerica-northeast1-a/clusters/projectfoo]. To inspect the contents of your cluster, go to: https://console.cloud.google.com/kubernetes/workload_/gcloud/northamerica-northeast1-a/projectfoo?project=projectfoo-208401 kubeconfig entry generated for projectfoo. NAME LOCATION MASTER_VERSION MASTER_IP MACHINE_TYPE NODE_VERSION NUM_NODES STATUS projectfoo northamerica-northeast1-a 1.8.10-gke.0 35.203.8.163 f1-micro 1.8.10-gke.0 3 RUNNING
With that done we can take a quick peek at what that last command created: a Kubernetes cluster on three f1-micro
VMs.
mike@sleepycat:~$ gcloud compute instances --project=projectfoo-208401 list NAME ZONE MACHINE_TYPE PREEMPTIBLE INTERNAL_IP EXTERNAL_IP STATUS gke-projectfoo-default-pool-190d2ac3-59hg northamerica-northeast1-a f1-micro 10.162.0.4 35.203.87.122 RUNNING gke-projectfoo-default-pool-190d2ac3-lbnk northamerica-northeast1-a f1-micro 10.162.0.2 35.203.78.141 RUNNING gke-projectfoo-default-pool-190d2ac3-pmsw northamerica-northeast1-a f1-micro 10.162.0.3 35.203.91.206 RUNNING
Let’s put those f1-micro
‘s to work. We are going to use the kubectl run
command to run a simple helloworld container that just has the basic output of create-react-app in it.
mike@sleepycat:~$ kubectl run projectfoo --image mikewilliamson/helloworld --port 3000 deployment "projectfoo" created
The result of that is the helloworld container, running inside a pod, inside a replica set inside a deployment, which of course is running inside a VM on Google Cloud. All that’s needed now is to map the port the container is listening on (3000) to port 80 so we can talk to it from the outside world.
mike@sleepycat:~$ kubectl expose deployment projectfoo --type LoadBalancer --port 80 --target-port 3000 service "projectfoo" exposed
This creates a LoadBalancer service, and eventually we get allocated our own IP.
mike@sleepycat:~$ kubectl get services NAME TYPE CLUSTER-IP EXTERNAL-IP PORT(S) AGE kubernetes ClusterIP 10.59.240.1 <none> 443/TCP 3m projectfoo LoadBalancer 10.59.245.55 <pending> 80:32184/TCP 34s mike@sleepycat:~$ kubectl get services NAME TYPE CLUSTER-IP EXTERNAL-IP PORT(S) AGE kubernetes ClusterIP 10.59.240.1 <none> 443/TCP 4m projectfoo LoadBalancer 10.59.245.55 35.203.123.204 80:32184/TCP 1m
Then we can use our newly allocated IP and talk to our container. The moment of truth!
mike@sleepycat:~$ curl 35.203.123.204 <!DOCTYPE html><html lang="en"><head><meta charset="utf-8"><meta name="viewport" content="width=device-width,initial-scale=1,shrink-to-fit=no"><meta name="theme-color" content="#000000"><link rel="manifest" href="/manifest.json"><link rel="shortcut icon" href="/favicon.ico"><title>React App</title><link href="/static/css/main.c17080f1.css" rel="stylesheet"></head><body><noscript>You need to enable JavaScript to run this app.</noscript><div id="root"></div><script type="text/javascript" src="/static/js/main.61911c33.js"></script></body></html>
After you’ve taken a moment to marvel at the layers of abstractions involved here, it’s worth remembering that you probably don’t want this stuff hanging around if you aren’t really using it, otherwise you’re going to regret connecting your billing information.
mike@sleepycat:~$ gcloud container --project projectfoo-208401 clusters delete projectfoo The following clusters will be deleted. - [projectfoo] in [northamerica-northeast1-a] Do you want to continue (Y/n)? y Deleting cluster projectfoo...done. Deleted [https://container.googleapis.com/v1/projects/projectfoo-208401/zones/northamerica-northeast1-a/clusters/projectfoo]. mike@sleepycat:~$ gcloud projects delete projectfoo-208401 Your project will be deleted. Do you want to continue (Y/n)? y Deleted [https://cloudresourcemanager.googleapis.com/v1/projects/projectfoo-208401]. You can undo this operation for a limited period by running: $ gcloud projects undelete projectfoo-208401
There is a lot going on here, and since this is new territory, much of it doesn’t mean lots to me yet. What’s exciting to me is finally being able to get a toe-hold on an otherwise pretty intimidating subject.
Having finally started working with it, I have to say both the kubectl
and gcloud
CLI tools are thoughtfully designed and pretty intuitive, and Google’s done a nice job making a lot of stuff happen in just a few approachable commands. I’m excited to dig in further.