Preparing CentOS 7 vRA templates with Ansible

In my lab I’m often spinning up new instances of vRealize Automation (vRA) and need to configure CentOS 7 templates. I created this Ansible playbook to get a freshly installed CentOS 7.2 minimal machine ready to be used by vRA. This is my first attempt and I’ll be modifying it to make it more usable. The playbook can be found at Github. Read the rest of this entry »


PowerCLI script to monitor recent vSphere Tasks

I haven’t had much time to look at vSphere 6.5 yet, but appearently the C# client is no more. I used to always have the C# client up as a diagnostic tool so that I could watch events trigger in real time as opposed to having to refresh the vSphere web client. Normally I’d open the C# client in full screen and then arrange my browsers so that they would cover the C# client but leave room so I’d be able to see the recent tasks pane. This would allow me to work in another product like vRealize Automation and see events appear in vCenter immediately.

If I can’t use the C# client to do this going forward, I thought I’d create a little PowerCLI script to provide me with the same information. I’m not sure how well it will work out yet, but you can find it on GitHub.

The result look like this:

2016-11-29_20-03-58.png


NetApp ONTAP 9 Simulator Guide by Neil Anderson

I want to take a moment to mention the great work Neal Anderson did in his NetApp ONTAP 9 Simulator Guide. This incredibly detailed (117 pages) guide not only shows you how to set up a NetApp ONTAP 9 simulator for your lab, but you’ll also learn how install/configure:

Storage is critical to any infrastructure and while you’re learning it’s easy to quickly install a storage solution that’s not representative of what you’ll see in the real world. I try to make my lab environment match what I see in real production environments as much as possible. That means using segregated networks with VLANs, firewalls, load balancers, CA signed certificates, and with the help this guide you’ll be able to implement a real world storage solution.


Listing all vCenter performance metrics with govmomi

In the past I wrote about how to List all vCenter performance counters with PowerCLI. In this post I’ll show how to do the same in Go with govmomi and compare the performance between the two.  I created the PowerCLI version of the script to gather vSphere performance counter information that I needed while creating the script in Gathering real-time vSphere performance metrics in parallel using PowerCLI. My goal is to create a Go version of this script using govmomi.

The code can be found at on github.

The performance counters are the same since it’s running against the same version of vCenter and can be found here.

You can also look at the vSphere performance counters through the vCenter mob by going to https://vcenter/mob/ and selecting content and then PerfMgr.

2016-09-26_22-16-56.png

2016-09-26_22-17-15.png

2016-09-26_22-17-34.png

If you’re not familiar with the vSphere API (like me), the mob can be a create place to explore and learn.

Code

The performance relevant pieces are highlighted towards the end.


package main

import (
        "context"
        "encoding/csv"
        "flag"
        "fmt"
        "log"
        "net/url"
        "os"
        "strings"

        "github.com/vmware/govmomi"
        "github.com/vmware/govmomi/vim25/mo"
)

// GetEnvString returns string from environment variable.
func GetEnvString(v string, def string) string {
        r := os.Getenv(v)
        if r == "" {
                return def
        }

        return r
}

// GetEnvBool returns boolean from environment variable.
func GetEnvBool(v string, def bool) bool {
        r := os.Getenv(v)
        if r == "" {
                return def
        }

        switch strings.ToLower(r[0:1]) {
        case "t", "y", "1":
                return true
        }

        return false
}

const (
        envURL      = "GOVMOMI_URL"
        envUserName = "GOVMOMI_USERNAME"
        envPassword = "GOVMOMI_PASSWORD"
        envInsecure = "GOVMOMI_INSECURE"
)

var urlDescription = fmt.Sprintf("ESX or vCenter URL [%s]", envURL)
var urlFlag = flag.String("url", GetEnvString(envURL, "https://username:password@host/sdk"), urlDescription)

var insecureDescription = fmt.Sprintf("Don't verify the server's certificate chain [%s]", envInsecure)
var insecureFlag = flag.Bool("insecure", GetEnvBool(envInsecure, false), insecureDescription)

func processOverride(u *url.URL) {
        envUsername := os.Getenv(envUserName)
        envPassword := os.Getenv(envPassword)

        // Override username if provided
        if envUsername != "" {
                var password string
                var ok bool

                if u.User != nil {
                        password, ok = u.User.Password()
                }

                if ok {
                        u.User = url.UserPassword(envUsername, password)
                } else {
                        u.User = url.User(envUsername)
                }
        }

        // Override password if provided
        if envPassword != "" {
                var username string

                if u.User != nil {
                        username = u.User.Username()
                }

                u.User = url.UserPassword(username, envPassword)
                        }
}

func exit(err error) {
        fmt.Fprintf(os.Stderr, "Error: %s\n", err)
        os.Exit(1)
}

func main() {
        ctx, cancel := context.WithCancel(context.Background())
        defer cancel()

        flag.Parse()

        // Parse URL from string
        u, err := url.Parse(*urlFlag)
        if err != nil {
                exit(err)
        }

        fmt.Println("u:", u)

        // Override username and/or password as required
        processOverride(u)

        // Connect and log in to ESX or vCenter
        client, err := govmomi.NewClient(ctx, u, *insecureFlag)
        if err != nil {
                exit(err)
        }

        if client.IsVC() {
                fmt.Println("connected to vCenter")
        } else {
                fmt.Println("connected to ESXi host")
        }

        var perfManager mo.PerformanceManager
        err = client.RetrieveOne(ctx, *client.ServiceContent.PerfManager, nil, &perfManager)
        perfCounters := perfManager.PerfCounter

        counterDetails := make([][]string, 0)

        for _, perfCounter := range perfCounters {
                groupInfo := perfCounter.GroupInfo.GetElementDescription()
                nameInfo := perfCounter.NameInfo.GetElementDescription()

                fullName := groupInfo.Key + "." + nameInfo.Key + "." + fmt.Sprint(perfCounter.RollupType)
                counterDetails = append(counterDetails, []string{fullName, fmt.Sprint(perfCounter.Level), nameInfo.Summary})
        }

        outputFile, err := os.Create("performanceCounters.csv")
        csvWriter := csv.NewWriter(outputFile)
        csvWriter.WriteAll(counterDetails)

        if err := csvWriter.Error(); err != nil {
                log.Fatalln("error writing csv:", err)
        }
}

Performance Results

This is hardly scientific, but here are the times it took to run the Go and Powershell versions of the script. I measured the runs three times and used the Powershell measure-command.

Ubuntu 14.04.5 LTS
go 1.7.1 776 ms
PowerCLI alpha for Linux 2259 ms
Windows 10
go 1.7.1 1746 ms
PowerCLI 6.0 Release 1 build 2548067 1639 ms

Hello Node.js on Rancher

In this post I’m going to show how to go through the Kubernetes Hello World Walkthrough but using Rancher instead of Google’s Cloud Platform. One of the reasons I wanted to install Kubernetes on my own resources instead of in the cloud is so that I don’t have to pay additional costs while I’m experimenting/learning.

You’ll need to have done the following before proceeding:

Create the Docker image

I’m going to build the Docker image on my Rancher machine (a VM), but you can build it anywhere. If you decide to build the Docker image somewhere other than the Rancher machine, you’ll need to push your image up to Docker Hub. You may be able to add a container registry to Rancher, but I haven’t explored that. You can also use my image.

Run the following on the Rancher machine.

mkdir hello-node
cd hello-node

Create a file named Dockerfile with the following contents:

FROM node:4.4
EXPOSE 8080
COPY server.js .
CMD node server.js

Create a file named server.js with the following contents:

var http = require(‘http’);
var handleRequest = function(request, response) {
response.writeHead(200);
response.end(“Hello World!”);
}
var www = http.createServer(handleRequest);
www.listen(8080);

Build the Docker image (that’s a period after v1):

docker build -t chrisgreene/hello-node:v1 .

If you need to upload the image to Docker Hub (make sure to change the image name or it will conflict with mine and fail):

docker login
docker push

Create the deployment

Now that we have our Docker image ready to go we can create the deployment. To do so:

  1. Make sure you’re in the Kubernetes (k8s) environment.
  2. Select Kubernetes
  3. Select Kubectl
  4. You’ll now have a shell to enter commands

2016-07-20_15-00-04.jpg

Enter the following command (replace the image name if you’re using your own):

kubectl run hello-node –image=chrisgreene/hello-node:v1 –port=8080

2016-07-20_14-57-01.jpg

If the deployment was successfully created, you’ll see the following:

2016-07-20_14-57-59.jpg

Verify our deployment:

2016-07-20_15-01-05.jpg

If we get all of the pods, we will see the hello-node pod:

2016-07-20_15-01-42.jpg

You can also view the replica sets by running kubectl get rs.

Select Infrastructure > Containers and you’ll see the hello-node containers:

2016-07-20_14-58-40.jpg

Expose the Node.js service to the outside

In order to reach the Node.js service, we need to expose it. We can do this with the following command:

kubectl expose deployment hello-node –port=80 –target-port=8080 –external-ip=192.168.3.168

192.168.3.168 is the IP of my Rancher machine. You’ll most likely need to change this. If you’re copy and pasting from this example, make sure there are two dashes in front of port, target-port and external-ip. Sometimes those get lost during copy/paste and the command won’t work.

2016-07-20_15-06-13.jpg

Let’s verify our service:

2016-07-20_15-06-56.jpg

Now I can access my Node.js app:

2016-07-20_15-12-34.jpg

Scale the app

Let’s scale the app to 4 replicas instead of one:

2016-07-20_15-14-50.jpg

Verify that we now have 4 pods:

2016-07-20_15-15-33.jpg

Upgrade the app

I’m not going to show the steps to upgrade the app, but they are exactly as described in Roll out an upgrade to your website.

I performed the steps and was able to see the new site:

2016-07-20_15-24-38.jpg


Deploying Kubernetes with Rancher

In a previous post I showed how to deploy Rancher. In this post I want to show how to deploy Kubernetes with Rancher and then deploy a simple application on top of Kubernetes. Please refer to the previous post for installation procedures for what OS to use and how to install docker. You can read up to “Start the Rancher Server” of that post and then come back to this post.

Starting the Rancher Server

You can skip this step if you’ve already started the Rancher server from the previous post. If not, let’s grab the latest version of Rancher and start the container. If you’re copying and pasting, make sure that there are two dashes before restart in the command below. Sometimes when I was copying and pasting the dashes would get converted into a single dash and the command would fail:

sudo docker run -d –restart=always -p 8080:8080 rancher/server

Now you should be able to access the Rancher application by opening a web browser and hitting the IP/URL of the VM where the Rancher container was launched.

We need to create a new environment so let’s:

  1. Highlight Default Environment
  2. Select Manage Environments

Create the kubernetes environment

2016-06-28_20-11-23.jpg

Select Add Environment

2016-06-28_20-20-56.jpg

  1. For Container Orchestration select kubernetes
  2. Provide a name
  3. Press Create

2016-06-28_20-22-24.jpg

To access the Kubernetes environment,

  1. Highlight Environment Default
  2. Select k8s

2016-06-28_20-38-24.jpg

Let’s go ahead and add the first host by selecting Add Host:

2016-06-28_20-40-33.jpg

On the next screen I’m going to use the IP address of the VM running my Rancher container to make things simpler by not having to worry about name resolution.

2016-06-28_20-50-45.jpg

On the next screen:

  1. Leave the host type as custom
  2. Select the clipboard to copy the command
  3. Press close
  4. Paste the command into the CLI of your VM running the Rancher container

2016-06-28_20-52-29.jpg

2016-06-28_20-33-52.jpgDocker should pull down the Rancher agent container:

2016-06-28_20-34-29.jpg

Kubernetes is now starting:

2016-06-28_20-42-48.jpg

If you want to see more details or troubleshoot an issue, select Infrastructure > Containers:

2016-06-28_20-54-50.jpg

Select Kubernetes > System to view all of the Kubernetes services:

2016-06-28_20-55-48.jpg

Launching a web server on Kubernetes

Now we are going to run a simple nginx server. Let’s first start by creating a new Replication Controller by selecting:

  1. Kubernetes
  2. Replication Controllers
  3. Add RC

2016-06-28_21-08-41.jpg

Paste in the following:

apiVersion: v1
kind: ReplicationController
metadata:
name: nginx
spec:
replicas: 2
selector:
app: nginx
template:
metadata:
name: nginx
labels:
app: nginx
spec:
containers:
– name: nginx
image: nginx
ports:
– containerPort: 80

To find out more about replication controllers, I’d suggest reading about them here, but I’ll cover a few things:

  • Replicas states that we want two containers running nginx
  • We apply the label app: nginx. This can be used to select the containers later.
  • image: nginx specifies the name of the docker iamge to pull down
  • We are going to expose port 80 on the container.

It shouldn’t take too long for both of the containers to be running. Notice the IP addresses. These IPs most likely won’t be accessible from your machine so you won’t have a way of accessing the nginx web server.

2016-06-28_21-15-43.jpg

We can access our nginx web servers by exposing them via a Kubernetes Service.

To create the service select:

  1. Kubernetes
  2. Services
  3. Add Service

2016-06-28_21-18-25.jpg

Paste in the following and press Create:

kind: Service
apiVersion: v1
metadata:
name: “nginx-service”
spec:
selector:
app: nginx
ports:
– name: http
protocol: TCP
port: 80
targetPort: 80
externalIPs:
– “192.168.3.168”

2016-06-28_21-05-32.jpg

The IP 192.168.3.168 is the IP of the VM running the Rancher/Kubernetes services.

If we expand our nginx-service, we can see that it’s associated with the two nginx containers. How did it do this? It used the selector app: nginx defined in the service  to find all containers with the label “app: nginx”. This is an important concept in Kubernetes.

2016-06-28_21-20-01.jpg

Now if I open a web browser and go to 192.168.3.168, I’ll see that nginx is running:

2016-06-28_21-23-28.jpg


Getting started with Rancher

A few days ago Rancher Labs released Rancher 1.0 so I’d thought I’d take it for a test drive. This is the first time I’ve worked with a product like this so this post will be really basic, but if this is the way things are going, it’s pretty amazing. Take a moment to check out their site and watch the “See Rancher in Action” video. The speaker sounds like a cowboy so you can imagine me talking like a cowboy for the rest of this post. I’m going to show how to deploy an application named Rocket Chat, which is like Slack. In my next post on Rancher I’ll show how to deploy Kubernetes using Rancher and then deploy and an application on Kubernetes.

Installation

I’m going to mainly be following the Quick Start Guide 

I started with a Ubuntu 12.04.5 LTS VM running on ESXi 5.1. My VM’s name is rancher1a.vmware.local with an IP of 192.168.3.168.

First let’s update the OS:

sudo apt-get update
sudo apt-get upgrade

Install the latest version of Docker by using the following commands or using Docker’s Instructions.

curl https://get.docker.com/ > docker-install.sh
Check out the docker-install.sh script to see what it’s doing.
chmod 700 docker-install.sh
./docker-install.sh

Adding myself into the docker group:

sudo usermod -aG docker chris

Start the Rancher server

We will run the Rancher server in a container by running:

sudo docker run -d –restart=always -p 8080:8080 rancher/server

Verify that the container is running:

2016-04-04_19-23-32.jpg

Now I can access Rancher by going to http://rancher1a.vmware.local:8080. You’ll be logged in automatically and will see the screen where you can add your first host:

2016-04-04_19-09-36.jpg

Go ahead and select Add Host and we see that the VM that is running Rancher has been pre-populated. For this demonstration I’m going to leave things as is and press Save.

2016-04-04_19-10-05.jpg

On the next screen, I’ll perform the following:

  1. Enter the IP of the VM where Ranch is running.
  2. Select the copy button
  3. Paste the copied text into the terminal running your Rancher container.
  4. Select Close

2016-04-04_19-12-59.jpg

Let’s verify that the Rancher agent container is running:

2016-04-04_19-23-32.jpg

Now go to:

  1. Infrastructure
  2. Hosts
  3. View the newly added host

2016-04-04_19-27-43.jpg

You can click on the hostname and view a bunch of info:

2016-04-04_19-29-39.jpg

Launching an App

We can view the built-in catalog by going to Catalog > All

2016-04-04_19-31-09.jpg

Let’s deploy the RocketChat app by selecting View Details:

2016-04-04_19-32-51.jpg

I’m going to leave everything at the defaults and select Launch:

2016-04-04_19-33-54.jpg

You should be redirected to Applications > Stacks where you can see the application starting up:

2016-04-04_19-38-53.jpg

At this point I like to switch over to the terminal that’s running the Rancher container and run the sudo watch docker ps command so that I can see the containers coming online.

2016-04-04_19-59-31.jpg

It shouldn’t take long for everything to become active:

2016-04-04_19-59-23.jpg

Now I can access the Rocket Chat instance at http://rancher1a.vmware.local:3000. From here you need to register for a new account:

2016-04-04_20-00-07.jpg

Fill in some info. The email address doesn’t have to be real:

2016-04-04_20-03-57.jpg

Acknowledge the warning that pops up and select a username:

2016-04-04_21-18-33.jpg

You’ll be logged in where you can begin using the application:

2016-04-04_21-20-24.jpg

The WordPress app is also simple to deploy so you may want to try that as well.