Adventures in CoreOS: The Saga Continues

I’ve worked with CoresOs in the past, but thought that two years was enough of a gap before I attempted to deal with it again.

In my original blog post, I had to handcraft individual ISOs for each CoreOS instance - this was painful and slow. Luckily, things have changed (for the better). CoreOS can now take advantage of VMware Tools and leverage properties present in the VM config file. With that knowledge, (and this blog post in hand), I opted to spin up a new three node cluster in my home lab.

The Script

I’ve built upon the original script from Robert Labrie, doing a bit of hard coding (my vCenter instance is temporary and still uses the default password for the [email protected] account). The final result can be found on GitHub.

Given a specified quantity of nodes, and a source template, several CoreOS VMs are deployed in vCenter. After the VMs are deployed, a cloud-config file must be provided to provide configuration for the new VMs. I’m leveraging a source yaml file for the bulk of the CoreOS configuration with specific information (networking, discovery URL, etc) generated by PowerShell script at run time. This configuration data is encoded with base64 and added to the VM’s vmx config file.

Helpful Tidbits

This bit requests a new discovery url with the given node count and updates the cloud-config.yml.

# Get a etcd cluster discovery url with the given size
$req = Invoke-WebRequest -Uri "https://discovery.etcd.io/new?size=$NodeCount"

# Get the current cloud-config content, then replace the existing discovery line with the new discovery url
# This is kludgey and should probably be replaced by yaml manipulation
get-content .\cloud-config.yml | ForEach-Object {$_ -replace "discovery: .*", "discovery: $($req.Content)"} | Set-Content .\cloud-config.yml

In order to allow variable size clusters, I’ve added a loop to build out the $vminfo hash.

# Iterate through the Nodes, buildig out $vmlist & $vminfo
for( [int]$Node = 1; $Node -le $NodeCount; $Node++)
{
	# list of machines to make - hostname will be set to this unless overridden
	$vmlist += "coreos$node"

	# Determine our IP
	$thisIP = ($IPAddressStart.Split(".")[0,1,2] -join ".")+"."+$([int]($IPAddressStart.Split(".")[3])+$Node)
	# Add hashmap of machine specific properties
	$vminfo["coreos$node"] = @{'interface.0.ip.0.address'="$thisIP/$Cidr"}
}

Converting cloud-config to base64 encoded data

if (Test-Path .\cloud-config.yml)
{
	# pull in the cloud config content
	$RawCloudConfig = Get-Content "cloud-config.yml" -raw
	
	# Encode as UTf8 in bytes
	$bytes = [System.Text.Encoding]::UTF8.GetBytes($RawCloudConfig)
	
	# Add to the properties hash the coreos config data & specify the encoding
	$gProps['coreos.config.data'] = [System.Convert]::ToBase64String($bytes)
	$gProps['coreos.config.data.encoding'] = 'base64'
}
else
{
	Throw "No cloud-config.yml found. Please create and add to this folder"
}

The actual injection into vmx

# get the file and strip out any existing guestinfo
$vmx = ((Get-Content $vmxLocal | Select-String -Pattern guestinfo -NotMatch) -join "`n").Trim()
$vmx = "$($vmx)`n"

# build the property bag
$props = $gProps
$props['hostname'] = $vmname
$vminfo[$vmname].Keys | ForEach-Object {
	$props[$_] = $vminfo[$vmname][$_]
}

# add to the VMX
$props.Keys | ForEach-Object {
	$vmx = "$($vmx)guestinfo.$($_) = ""$($props[$_])""`n" 
}

# write out the VMX
$vmx | Out-File $vmxLocal -Encoding ascii