Installing and Running a Local Kubernetes Environment on macOS

how to install and run a local kubernetes environment on macos

Background

For a local installation of Kubernetes on macOS the getting started guide recommends minikube is used. This page details the various installation steps required to install this.

Prerequisites

Ensure that the software below is installed on the host macOS machine before continuing.
* Docker for Mac
* Homebrew

Installing minikube

As per the minikube documentation

“Minikube is a tool that makes it easy to run Kubernetes locally. Minikube runs a single-node Kubernetes cluster inside a VM on your laptop for users looking to try out Kubernetes or develop with it day-to-day.”

To install minikube, follow the instructions at https://github.com/kubernetes/minikube/releases. At the time of writing, version v0.15.0 is the latest release; the appropriate installation commands for this version are as follows:

curl -Lo minikube https://storage.googleapis.com/minikube/releases/v0.15.0/minikube-darwin-amd64 && chmod +x minikube && sudo mv minikube /usr/local/bin/

Installing the xhyve Driver

By default, minikube uses VirtualBox to host the Kubernetes environment. However, as Docker for Mac uses xhyve, it makes more sense to use the same hypervisor to host our Kubernetes environment.

For this we need to install the appropriate xhyve driver as detailed at https://github.com/kubernetes/minikube/blob/master/DRIVERS.md#xhyve-driver

At the time of writing, the appropriate installation commands for this are as follows:

$ brew install docker-machine-driver-xhyve
$ sudo chown root:wheel $(brew --prefix)/opt/docker-machine-driver-xhyve/bin/docker-machine-driver-xhyve
$ sudo chmod u+s $(brew --prefix)/opt/docker-machine-driver-xhyve/bin/docker-machine-driver-xhyve

Installing kubectl

In order to control Kubernetes from the command-line, the kubectl tool is used. Refer to https://kubernetes.io/docs/user-guide/kubectl for more information.

To install kubectl, follow the instructions at https://kubernetes.io/docs/user-guide/prereqs. At the time of writing the latest stable version is v1.5.2; the appropriate installation commands for this version are as follows:

$ curl -LO https://storage.googleapis.com/kubernetes-release/release/$(curl -s https://storage.googleapis.com/kubernetes-release/release/stable.txt)/bin/darwin/amd64/kubectl
$ chmod +x ./kubectl
$ sudo mv ./kubectl /usr/local/bin/kubectl

Starting, Verifying, Inspecting and Stopping minikube

Starting minikube is trivial, as shown below. The first time this command is executed will take longer than for subsequent calls as it will pull the ISO, storing in ~/.minikube/cache/iso/.

$ minikube start --vm-driver=xhyve
Starting local Kubernetes cluster...
Downloading Minikube ISO
 68.95 MB / 68.95 MB [==============================================] 100.00% 0s
Kubectl is now configured to use the cluster.

Verify the status of minikube:

$ minikube status
minikubeVM: Running
localkube: Running

Inspect the environment by bringing up the dashboard, which will open up in the browser.

$ minikube dashboard
Opening kubernetes dashboard in default browser...

Stop the minikube environment:

$ minikube stop
Stopping local Kubernetes cluster...
Machine stopped.

Using Docker for Mac Behind the Corporate Proxy

how to use docker for mac when behind a corporate proxy

Background

Although enabling internet access for Docker for Mac when behind a corporate proxy appears to be difficult, the steps required are surprisingly simple.

Prerequisite

A local proxy server should be running on the Mac where Docker is running in order to authenticate with the dreaded corporate proxy. Both Charles Proxy and SquidMan work well for this purpose. It is assumed below that the local proxy server is listening on port 8099; feel free to change this value throughout, if required.

Getting the IP Address of the Docker VM Gateway

Connect to the VM, as detailed in Accessing the Docker For Mac Virtual Machine.

$ screen ~/Library/Containers/com.docker.docker/Data/com.docker.driver.amd64-linux/tty

Press the Enter key, and validate we are on the Docker VM.

/ # hostname
moby

Examine the routing table to see the default gateway: in the example below, this is 192.168.65.1

/ # netstat -rn
Kernel IP routing table
Destination     Gateway         Genmask         Flags   MSS Window  irtt Iface
0.0.0.0         192.168.65.1    0.0.0.0         UG        0 0          0 eth0
172.17.0.0      0.0.0.0         255.255.0.0     U         0 0          0 docker0
172.18.0.0      0.0.0.0         255.255.0.0     U         0 0          0 br-b46215017f01
192.168.65.0    0.0.0.0         255.255.255.248 U         0 0          0 eth0

Disconnect from the VM using ctrl a \, answering y to the prompt:

Really quit and kill all your windows [y/n] y

Set the Docker for Mac Proxy

Finally, set the proxy in Docker itself, as shown below:
Docker for Mac Proxy Settings

The IP address is the gateway IP address from the Docker VM (i.e. 192.168.65.1); the port is what the local proxy is listening on (i.e. 8099). Apply the changes and restart Docker, at which point it will now be able to communicate, via the local proxy server, to the internet. Easy!

Getting Started with golang on macOS

how to install golang using homebrew and how to set the necessary environment variables

Installing golang using Homebrew

First install golang using Homebrew as follows:

$ brew install golang

This will install to the following location:

$ which go
/usr/local/bin/go

Setting GOROOT

The golang binary distributions expect to be installed to the standard location of /usr/local/go. This will not be the case, as Homebrew installs into /usr/local/bin/go, so we need to manually set the GOROOT environment variable to point the correct location as follows:

export GOROOT=/usr/local/opt/go/libexec

See https://golang.org/doc/install#tarball_non_standard for more information on GOROOT.

Setting GOPATH

First set a DEVELOPMENT_HOME environment variable. This will point to the top-level directory under which all code artefacts will exist, regardless of language.

export DEVELOPMENT_HOME=$HOME/Development

Next, set the GOPATH environment variable. This will point to the root directory where all golang-related artefacts will exist. Make this a direct subdirectory of the DEVELOPMENT_HOME directory.

export GOPATH=$DEVELOPMENT_HOME/golang

See https://golang.org/cmd/go/#hdr-GOPATH_environment_variable for information on GOPATH.

Test the Installation

$ go get github.com/golang/example/hello

$ ls $GOPATH/src/github.com/golang/example/hello
hello.go

$ ls $GOPATH/bin/hello
-rwxr-xr-x  1 paul  staff   1603584  9 Dec 18:03 hello

$ $GOPATH/bin/hello
Hello, Go examples!

See https://golang.org/doc/code.html#remote for more information.

Accessing the Docker For Mac Virtual Machine

how to access the docker for mac virtual machine

Background

Although Docker for Mac helpfully goes out of its way to appear to be running natively on macOS, behind the scenes it actually runs on an Alpine Linux VM using xhyve. Refer to https://docs.docker.com/engine/installation/mac/ for more details.

Under most circumstances we won’t need to understand the underlying implementation, but there are occasions where it is helpful to be able to see exactly what Docker is doing. In order to do this, we need access to the actual VM itself. This isn’t a problem when using Docker Machine as we can easily connect to the VirtualBox VM; it is not quite so obvious how to achieve this on the new architecture.

Accessing the Docker Device

The callin device for the Docker VM can be found at ~/Library/Containers/com.docker.docker/Data/com.docker.driver.amd64-linux/tty.

$ ls -l ~/Library/Containers/com.docker.docker/Data/com.docker.driver.amd64-linux/tty
lrwxr-xr-x  1 paul  staff  12 18 Oct 16:54 /Users/paul/Library/Containers/com.docker.docker/Data/com.docker.driver.amd64-linux/tty -> /dev/ttys001

As can be seen above, this file is actually a link to the underlying character device file:

$ ls -l /dev/ttys001
crw--w----  1 paul  tty   16,   1 18 Oct 16:54 /dev/ttys001

To access this device interactively, we can simply use the screen utility as follows:

$ screen ~/Library/Containers/com.docker.docker/Data/com.docker.driver.amd64-linux/tty

If the resulting screen is blank, simply hit the Enter key; you should then be presented with the following:

Welcome to Moby
Kernel 4.4.20-moby on an x86_64 (/dev/ttyS0)

                        ##         .
                  ## ## ##        ==
               ## ## ## ## ##    ===
           /"""""""""""""""""___/ ===
      ~~~ {~~ ~~~~ ~~~ ~~~~ ~~~ ~ /  ===- ~~~
           \______ o           __/
             \    \         __/
              \____\_______/

moby login: root
Welcome to Moby, based on Alpine Linux.
moby:~#

As shown, the login is root; no password is required. And that’s all there is to it: you now have a session on the Docker VM.

For example, to check the Docker images that have been loaded on your Docker for Mac installation:

moby:~# docker images
REPOSITORY                           TAG                 IMAGE ID            CREATED             SIZE
ubuntu                               16.04               c73a085dc378        3 weeks ago         127.1 MB
tykio/tyk-gateway                    latest              34c572d12a1f        9 weeks ago         246.9 MB
redis                                latest              e5181bd07b8e        10 weeks ago        185 MB
swaggerapi/swagger-editor            latest              3727b21e15fc        3 months ago        105.6 MB
tykio/tyk-dashboard                  latest              6249f7af1db2        3 months ago        567.1 MB
tykio/tyk-pump-docker-pub            latest              b0df8680eaab        3 months ago        246.7 MB
alpine                               3.3                 47cf20d8c26c        3 months ago        4.797 MB
jenkins                              latest              d5c0410b1b44        4 months ago        736.9 MB
registry                             latest              bca04f698ba8        8 months ago        422.9 MB
moby:~#

That’s Great … But How do I Get Out of Here?

The key combination you’re looking for is ctrl a \ then answer y to the prompt:

Really quit and kill all your windows [y/n] y

Creating a Custom/Alternative Maven Lifecycle

how to create a custom/alternative maven lifecycle

Creating a custom lifecycle in Maven is pretty straightforward, although there doesn’t seem to be many examples available online. This post details how to create a custom lifecycle – i.e. not one of the default three Maven lifecycles – and optionally set default goals for the phases.

The complete source code for the examples below can pulled from the https://github.com/nextmetaphor/maven repository.

Create a Plugin

To create your own custom lifecycle you need to create a Maven plugin which only requires two files: pom.xml and components.xml

Setting up the Directory Structure

The diagram below shows where these files should be located. Note that this directory structure also contains the CustomLifecyclePluginPhase1Mojo.java mojo; this is not actually required for the custom lifecycle, and is simply used to validate when a particular phase is called later on.

Plugin Directory Structure

Configuring the pom.xml File

The pom.xml file is very straightforward, we are simply creating a maven-plugin.

    <project xmlns="http://maven.apache.org/POM/4.0.0" 
        xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance" 
        xsi:schemaLocation="http://maven.apache.org/POM/4.0.0
        http://maven.apache.org/maven-v4_0_0.xsd">
      <modelVersion>4.0.0</modelVersion>

      <groupId>com.nextmetaphor.plugin</groupId>
      <artifactId>CustomLifecyclePlugin</artifactId>
      <version>1.0-SNAPSHOT</version>
      <packaging>maven-plugin</packaging>
      <name>Custom Lifecycle Plugin</name>

      <dependencies>
        <dependency>
          <groupId>org.apache.maven</groupId>
          <artifactId>maven-plugin-api</artifactId>
          <version>2.0</version>
        </dependency>
      </dependencies>
    </project>

Configuring the components.xml File

Configuring the components.xml file is also straightforward, the interesting fields are explained in more detail below:

    <component-set>
      <components>
        <component>
          <role>org.apache.maven.lifecycle.Lifecycle</role>
          <role-hint>customLifecyclePlugin_PackagingType</role-hint>
          <implementation>org.apache.maven.lifecycle.Lifecycle</implementation>
          <configuration>
            <id>customLifecyclePlugin_LifecycleID</id>
            <phases>
              <phase>phase1</phase>
              <phase>phase2</phase>
              <phase>phase3</phase>
            </phases>
            <default-phases>
              <phase1>com.nextmetaphor.plugin:CustomLifecyclePlugin:phase1Goal</phase1>
            </default-phases>
          </configuration>
        </component>
      </components>
    </component-set>

For this particular example, the actual value of role-hint doesn’t appear to be used, although it looks to be a mandatory field and therefore cannot be removed. More useful is the id field, this is the name of the custom lifecycle being created, to complement the existing Maven lifecycles of clean, default and site.

The various phase elements detail the phases for the lifecycle in the order they will run. Finally, any phase that should default to a particular plugin goal should be defined in the default-phases section. In the example above, the first phase of the custom lifecycle – phase1 – will by default call the phase1Goal on the CustomLifecyclePlugin in the com.nextmetaphor.plugin group.

And that’s all there is to it! Simply mvn install this plugin and we can use the new custom lifecycle from another project.

Create A Project To Use The Custom Lifecycle

This demonstration project consists solely of a simple pom.xml file.

Configuring the pom.xml File

Here the custom lifecycle is introduced by the plugin reference. Note that the extensions property must be set to true for the custom lifecycle to become available to us.

    <project xmlns="http://maven.apache.org/POM/4.0.0"
        xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance"
        xsi:schemaLocation="http://maven.apache.org/POM/4.0.0
        http://maven.apache.org/xsd/maven-4.0.0.xsd">
      <modelVersion>4.0.0</modelVersion>

      <groupId>com.nextmetaphor.project</groupId>
      <artifactId>CustomLifecycleProject</artifactId>
      <version>1.0-SNAPSHOT</version>
      <packaging>jar</packaging>
      <name>Custom Lifecycle Project</name>

      <build>
        <plugins>
          <plugin>
              <groupId>com.nextmetaphor.plugin</groupId>
              <artifactId>CustomLifecyclePlugin</artifactId>
              <version>1.0-SNAPSHOT</version>
              <extensions>true</extensions>
          </plugin>
        </plugins>
      </build> 
    </project>

Confirming the Custom Lifecycle is Available

Invoke the clean phase on the project with verbose debug on using mvn clean -X. This should complete successfully. Scroll back through the logs until the available lifecycles are listed:

    [INFO] ------------------------------------------------------------------------
    [INFO] Building Custom Lifecycle Project 1.0-SNAPSHOT
    [INFO] ------------------------------------------------------------------------
    [DEBUG] Lifecycle default -> [validate, initialize, generate-sources,
            process-sources, generate-resources, process-resources, compile,
            process-classes, generate-test-sources, process-test-sources, 
            generate-test-resources, process-test-resources, test-compile, 
            process-test-classes, test, prepare-package, package, 
            pre-integration-test, integration-test, post-integration-test, 
            verify, install, deploy]
    [DEBUG] Lifecycle clean -> [pre-clean, clean, post-clean]
    [DEBUG] Lifecycle site -> [pre-site, site, post-site, site-deploy]
    [DEBUG] Lifecycle customLifecyclePlugin_LifecycleID -> [phase1, 
            phase2, phase3]

Invoking the Custom Lifecycle

As a final test we’ll invoke the phase3 phase which should invoke the preceding phases: phase1 and phase2. Only phase1 has been set up with a default goal, in this case to call a mojo which will simply output some text.

    [CustomLifecycleProject]$ mvn phase3
    [INFO] Scanning for projects...
    [INFO]                                                                         
    [INFO] ------------------------------------------------------------------------
    [INFO] Building Custom Lifecycle Project 1.0-SNAPSHOT
    [INFO] ------------------------------------------------------------------------
    [INFO] 
    [INFO] --- 
           CustomLifecyclePlugin:1.0-SNAPSHOT:phase1Goal(default-phase1Goal)
           @ CustomLifecycleProject ---
    [INFO] Doing Phase 1 stuff. Oh yeah baby.
    [INFO] ------------------------------------------------------------------------
    [INFO] BUILD SUCCESS
    [INFO] ------------------------------------------------------------------------
    [INFO] Total time: 0.755s
    [INFO] Finished at: Tue Jan 28 01:00:58 GMT 2014
    [INFO] Final Memory: 5M/141M
    [INFO] ------------------------------------------------------------------------