I'm working on writing custom controller for our kubernetes cluster and that'll listen to node events and perform some operation on the node.I'm using kubernetes client-go library and able to capture kubernetes events whenever a node is attached or removed from the cluster. But is it possible to get AWS instance details of kubernetes node that has been created like instance id, tags etc ? Thanks in advance.
PS: I have installed the kubernetes cluster using kops
On receiving the event for node creation, it's object object's attribute Name object.Name has the private dns of the aws instance that was created. Using the private dns of the instance, we could query for instance-id using aws-sdk-go
hostName := object.Name
sess := session.Must(session.NewSessionWithOptions(session.Options{
SharedConfigState: session.SharedConfigEnable,
}))
// Create new EC2 client
ec2Svc := ec2.New(sess)
var instanceId string
params := &ec2.DescribeInstancesInput{
Filters: []*ec2.Filter{
{
Name: aws.String("private-dns-name"),
Values: []*string{aws.String(hostName)},
},
},
}
// Call to get detailed information on each instance
result, err := ec2Svc.DescribeInstances(params)
if err != nil {
fmt.Println("there was an error listing instances in", err.Error())
log.Fatal(err.Error())
}
for idx, res := range result.Reservations {
fmt.Println(" > Reservation Id", *res.ReservationId, " Num Instances: ", len(res.Instances))
for _, inst := range result.Reservations[idx].Instances {
// result[idx].SetDisableApiTermination(true);
instanceId = *inst.InstanceId
fmt.Println(" - Instance ID: ", *inst.InstanceId)
break // Only one instance will match the private dns
}
}
With the instance id, we could perform any operations on the ec2 instance using aws-sdk-go API's.
On a Kubernetes node in AWS, you'll have some things populated as part of the node labels and various other parts of the node's metadata:
kubectl get nodes -o json | jq '.items[].metadata.labels'
{
"beta.kubernetes.io/arch": "amd64",
"beta.kubernetes.io/instance-type": "c5.large",
"beta.kubernetes.io/os": "linux",
"failure-domain.beta.kubernetes.io/region": "us-east-1",
"failure-domain.beta.kubernetes.io/zone": "us-east-1b",
"kubernetes.io/hostname": "<hostname>",
"kubernetes.io/role": "master",
"manufacturer": "amazon_ec2",
"node-role.kubernetes.io/master": "",
"operatingsystem": "centos",
"tier": "production",
"virtual": "kvm"
}
The node information is in client-go
in the node package here using the Get
method. Here's an example:
client := kubernetes.NewForConfigOrDie(config)
list, err := client.CoreV1().Nodes().List(metav1.ListOptions{})
if err != nil {
fmt.Fprintf(os.Stderr, "error listing nodes: %v", err)
os.Exit(1)
}
for _, node := range list.Items {
fmt.Printf("Node: %s\n", node.Name)
node, err := client.CoreV1().Nodes().Get(node.Name, metav1.GetOptions{})
if err != nil {
fmt.Fprintf(os.Stderr, "error getting node: %v", err)
os.Exit(1)
}
fmt.Println(node)
}
However this is really probably not the way you want to go about it. If you're running this on a kops cluster in AWS, the node your workload is running on already has access to the AWS API and also the IAM role needed to query node data.
With that in mind, please consider using the AWS Go SDK instead. You can query EC2 quite easily, here's an adapted example:
package main
import (
"fmt"
"github.com/aws/aws-sdk-go/aws"
"github.com/aws/aws-sdk-go/aws/session"
"github.com/aws/aws-sdk-go/service/ec2"
)
func main() {
// Load session from shared config
sess := session.Must(session.NewSessionWithOptions(session.Options{
SharedConfigState: session.SharedConfigEnable,
}))
// Create new EC2 client
ec2Svc := ec2.New(sess)
// Call to get detailed information on each instance
result, err := ec2Svc.DescribeInstances(nil)
if err != nil {
fmt.Println("Error", err)
} else {
fmt.Println("Success", result)
}
}