How to create multi instance in google cloud functions with golang

huangapple go评论70阅读模式
英文:

How to create multi instance in google cloud functions with golang

问题

我正在尝试在GCP中使用云函数创建多个实例,并使用Golang编程。

我参考了https://medium.com/google-cloud/using-cloud-scheduler-and-cloud-functions-to-deploy-a-periodic-compute-engine-vm-worker-2b897ef68dc5中的教程,然后在我的上下文中进行了一些自定义。以下是我的代码:

package cloudfunctions

import (
	"context"
	"fmt"
	"log"
	"net/http"
	"os"
	"google.golang.org/api/compute/v1"
)

var ProjectID = ""
var Zone = ""
var Region = ""
var InstanceName = ""
var InstanceType = ""

func DeployInstance(w http.ResponseWriter, r *http.Request) {
	ProjectID = os.Getenv("PROJECT_ID")
	Zone = os.Getenv("ZONE")
	Region = os.Getenv("REGION")

	cs, err := InitComputeService()
	if err != nil {
		w.WriteHeader(http.StatusInternalServerError)
		log.Fatal(err)
	}

	var listInstance = []string{"e2-standard-2", "e2-standard-8", "n2-standard-2", "n2-standard-8", "n1-custom-2-8192", "n1-custom-8-32768", "c2-standard-8" }
	for i:=0; i < 7; i++ {
		InstanceType = listInstance[i]
		InstanceName = "benchmark-"+InstanceType
		
		instance, err := GetInstance(cs)
		if err != nil {
			w.WriteHeader(http.StatusTemporaryRedirect)
			w.Write([]byte(err.Error() + " instance may not exist yet"))
			log.Print(err)
	
			_, err = CreateInstance(cs)
			if err != nil {
				w.WriteHeader(http.StatusInternalServerError)
				w.Write([]byte("creating instance " + InstanceName + "in zone: " + Zone))
				startInstance(cs, w)
			}
	
		} else {
			msg := "instance is in intermediate state: " + instance.Status
			w.WriteHeader(http.StatusAccepted)
			w.Write([]byte(msg))
			log.Println(msg)
			
		}
	}
}

func InitComputeService() (*compute.Service, error) {
	ctx := context.Background()
	return compute.NewService(ctx)
}

func GetInstance(computeService *compute.Service) (*compute.Instance, error) {
	return computeService.Instances.Get(ProjectID, Zone, InstanceName).Do()
}


func StartInstance(computeService *compute.Service) (*compute.Operation, error) {
	return computeService.Instances.Start(ProjectID, Zone, InstanceName).Do()
}

// CreateInstance creates a given instance with metadata that logs its information.
func CreateInstance(computeService *compute.Service) (*compute.Operation, error) {

	instance := &compute.Instance{
		Name: InstanceName,
		MachineType: fmt.Sprintf("zones/%s/machineTypes/%s", Zone, InstanceType),
		NetworkInterfaces: []*compute.NetworkInterface{
			{
				Name:       "default",
				Subnetwork: fmt.Sprintf("projects/%s/regions/%s/subnetworks/default", ProjectID, Region),
				AccessConfigs: []*compute.AccessConfig{
					{
						Name:        "External NAT",
						Type:        "ONE_TO_ONE_NAT",
						NetworkTier: "PREMIUM",
					},
				},
			},
		},
		Scheduling: &compute.Scheduling{
			Preemptible: true,
		},
		Disks: []*compute.AttachedDisk{
			{
				Boot:       true,         // The first disk must be a boot disk.
				AutoDelete: true,         //Optional
				Mode:       "READ_WRITE", //Mode should be READ_WRITE or READ_ONLY
				Interface:  "SCSI",       //SCSI or NVME - NVME only for SSDs
				InitializeParams: &compute.AttachedDiskInitializeParams{
					DiskName: "worker-instance-boot-disk",
					SourceImage: "projects/centos-cloud/global/images/family/centos-7",
					DiskType:    fmt.Sprintf("projects/%s/zones/%s/diskTypes/pd-ssd", ProjectID, Zone),
					DiskSizeGb:  200,
				},
			},
		},
	}
	return computeService.Instances.Insert(ProjectID, Zone, instance).Do()
}

// startInstance is a wrapper function for the switch statement
func startInstance(cs *compute.Service, w http.ResponseWriter) {
	operation, err := StartInstance(cs)
	if err != nil {
		w.WriteHeader(http.StatusInternalServerError)
		log.Fatal(err)
	}
	w.WriteHeader(http.StatusOK)
	data, _ := operation.MarshalJSON()
	w.Write(data)

}

在上面的代码中,我想创建7个具有7个不同设置的实例,具体是实例类型和实例名称。我在云函数中测试了这段代码,其中DeployInstance是启动函数。但是只创建了一个实例,名称为benchmark-e2-standard-2,类型为e2-standard-2。它输出了一个错误,错误消息为Error: Infrastructure cannot communicate with function. There was likely a crash or deadlock in the user-provided code. Additional troubleshooting documentation can be found at https://cloud.google.com/functions/docs/troubleshooting#logging

我访问了网站,但没有找到解决我的代码的方法。谁能帮我解决为什么我的代码不正确,如何修复它。如果可能的话,逐步解释一下。提前感谢。

英文:

I am trying to create multi instance in GCP with cloud function, use golang programing.

I refer tutorial in https://medium.com/google-cloud/using-cloud-scheduler-and-cloud-functions-to-deploy-a-periodic-compute-engine-vm-worker-2b897ef68dc5 then write some customize in my context. Here is my code

package cloudfunctions
import (
&quot;context&quot;
&quot;fmt&quot;
&quot;log&quot;
&quot;net/http&quot;
&quot;os&quot;
&quot;google.golang.org/api/compute/v1&quot;
)
var ProjectID = &quot;&quot;
var Zone = &quot;&quot;
var Region = &quot;&quot;
var InstanceName = &quot;&quot;
var InstanceType = &quot;&quot;
func DeployInstance(w http.ResponseWriter, r *http.Request) {
ProjectID = os.Getenv(&quot;PROJECT_ID&quot;)
Zone = os.Getenv(&quot;ZONE&quot;)
Region = os.Getenv(&quot;REGION&quot;)
cs, err := InitComputeService()
if err != nil {
w.WriteHeader(http.StatusInternalServerError)
log.Fatal(err)
}
var listInstance = []string{&quot;e2-standard-2&quot;, &quot;e2-standard-8&quot;, &quot;n2-standard-2&quot;, &quot;n2-standard-8&quot;, &quot;n1-custom-2-8192&quot;, &quot;n1-custom-8-32768&quot;, &quot;c2-standard-8&quot; }
for i:=0; i &lt; 7; i++ {
InstanceType = listInstance[i]
InstanceName = &quot;benchmark-&quot;+InstanceType
instance, err := GetInstance(cs)
if err != nil {
w.WriteHeader(http.StatusTemporaryRedirect)
w.Write([]byte(err.Error() + &quot; instance may not exist yet&quot;))
log.Print(err)
_, err = CreateInstance(cs)
if err != nil {
w.WriteHeader(http.StatusInternalServerError)
w.Write([]byte(&quot;creating instance &quot; + InstanceName + &quot;in zone: &quot; + Zone))
startInstance(cs, w)
}
} else {
msg := &quot;instance is in intermediate state: &quot; + instance.Status
w.WriteHeader(http.StatusAccepted)
w.Write([]byte(msg))
log.Println(msg)
}
}
}
func InitComputeService() (*compute.Service, error) {
ctx := context.Background()
return compute.NewService(ctx)
}
func GetInstance(computeService *compute.Service) (*compute.Instance, error) {
return computeService.Instances.Get(ProjectID, Zone, InstanceName).Do()
}
func StartInstance(computeService *compute.Service) (*compute.Operation, error) {
return computeService.Instances.Start(ProjectID, Zone, InstanceName).Do()
}
// CreateInstance creates a given instance with metadata that logs its information.
func CreateInstance(computeService *compute.Service) (*compute.Operation, error) {
instance := &amp;compute.Instance{
Name: InstanceName,
MachineType: fmt.Sprintf(&quot;zones/%s/machineTypes/%s&quot;, Zone, InstanceType),
NetworkInterfaces: []*compute.NetworkInterface{
{
Name:       &quot;default&quot;,
Subnetwork: fmt.Sprintf(&quot;projects/%s/regions/%s/subnetworks/default&quot;, ProjectID, Region),
AccessConfigs: []*compute.AccessConfig{
{
Name:        &quot;External NAT&quot;,
Type:        &quot;ONE_TO_ONE_NAT&quot;,
NetworkTier: &quot;PREMIUM&quot;,
},
},
},
},
Scheduling: &amp;compute.Scheduling{
Preemptible: true,
},
Disks: []*compute.AttachedDisk{
{
Boot:       true,         // The first disk must be a boot disk.
AutoDelete: true,         //Optional
Mode:       &quot;READ_WRITE&quot;, //Mode should be READ_WRITE or READ_ONLY
Interface:  &quot;SCSI&quot;,       //SCSI or NVME - NVME only for SSDs
InitializeParams: &amp;compute.AttachedDiskInitializeParams{
DiskName: &quot;worker-instance-boot-disk&quot;,
SourceImage: &quot;projects/centos-cloud/global/images/family/centos-7&quot;,
DiskType:    fmt.Sprintf(&quot;projects/%s/zones/%s/diskTypes/pd-ssd&quot;, ProjectID, Zone),
DiskSizeGb:  200,
},
},
},
}
return computeService.Instances.Insert(ProjectID, Zone, instance).Do()
}
// startInstance is a wrapper function for the switch statement
func startInstance(cs *compute.Service, w http.ResponseWriter) {
operation, err := StartInstance(cs)
if err != nil {
w.WriteHeader(http.StatusInternalServerError)
log.Fatal(err)
}
w.WriteHeader(http.StatusOK)
data, _ := operation.MarshalJSON()
w.Write(data)
}

In above code, I want to create 7 instance with 7 difference setting, specific is instance type and instance name. I test this code in cloud function with DeployInstance is start function. But there is only one instance was created, with name is benchmark-e2-standard-2 and type is e2-standard-2. It output an error with message Error: Infrastructure cannot communicate with function. There was likely a crash or deadlock in the user-provided code. Additional troubleshooting documentation can be found at https://cloud.google.com/functions/docs/troubleshooting#logging

I visited website but I not find a solution to fix my code. Who can help me why my code not true, how can I fix it. Step by step if possible.
Thanks in advance.

答案1

得分: 0

我找到了答案。根本原因是每个实例必须有一个磁盘分区,并且分区的名称必须不同。

所以,我对代码进行了一些更改,你可以在下面看到。

package cloudfunctions

import (
	"context"
	"fmt"
	"log"
	"net/http"
	"os"
	"google.golang.org/api/compute/v1"
	"time"
)

var ProjectID = ""
var Zone = ""
var Region = ""
var InstanceName = ""
var InstanceType = ""
var IDiskName = ""

func DeployInstance(w http.ResponseWriter, r *http.Request) {
	ProjectID = os.Getenv("PROJECT_ID")
	Zone = os.Getenv("ZONE")
	Region = os.Getenv("REGION")

	var listInstance = []string{"e2-standard-8","e2-standard-2",  "n2-standard-2", "n2-standard-8", "n1-custom-2-8192", "n1-custom-8-32768", "c2-standard-8"}
	for i:=0; i < len(listInstance); i++ {
		cs, err := compute.NewService(context.Background())
		if err != nil {
			w.WriteHeader(http.StatusInternalServerError)
			log.Fatal(err)
		}
		InstanceType = listInstance[i]
		InstanceName = "benchmark-"+InstanceType
		IDiskName = InstanceName+"-boot-disk"

		instance, err := GetInstance(cs)
		if err != nil {
			w.WriteHeader(http.StatusTemporaryRedirect)
			w.Write([]byte(err.Error() + " instance may not exist yet"))

			_, err = CreateInstance(cs)
			if err != nil {
				for {
					disk, derr := cs.Disks.Get(ProjectID, Zone, IDiskName).Context(context.Background()).Do()
					log.Print(IDiskName + " is " + disk.Status)
					time.Sleep(1 * time.Second)
					if derr != nil {
						startInstance(cs, w)
						break
					}
				}
				
			}
		} else {
			msg := "instance "+ InstanceName +" is in intermediate state: " + instance.Status
			w.WriteHeader(http.StatusAccepted)
			w.Write([]byte(msg))
			log.Println(msg)
		}
	}
}


func GetInstance(computeService *compute.Service) (*compute.Instance, error) {
	return computeService.Instances.Get(ProjectID, Zone, InstanceName).Do()
}


func StartInstance(computeService *compute.Service) (*compute.Operation, error) {
	return computeService.Instances.Start(ProjectID, Zone, InstanceName).Do()
}

// CreateInstance creates a given instance with metadata that logs its information.
func CreateInstance(computeService *compute.Service) (*compute.Operation, error) {
	instance := &compute.Instance{
		Name: InstanceName,
		MachineType: fmt.Sprintf("zones/%s/machineTypes/%s", Zone, InstanceType),
		NetworkInterfaces: []*compute.NetworkInterface{
			{
				Name:       "default",
				Subnetwork: fmt.Sprintf("projects/%s/regions/%s/subnetworks/default", ProjectID, Region),
				AccessConfigs: []*compute.AccessConfig{
					{
						Name:        "External NAT",
						Type:        "ONE_TO_ONE_NAT",
						NetworkTier: "PREMIUM",
					},
				},
			},
		},
		Scheduling: &compute.Scheduling{
			Preemptible: true,
		},
		Disks: []*compute.AttachedDisk{
			{
				Boot:       true,         // The first disk must be a boot disk.
				AutoDelete: true,         //Optional
				Mode:       "READ_WRITE", //Mode should be READ_WRITE or READ_ONLY
				Interface:  "SCSI",       //SCSI or NVME - NVME only for SSDs
				InitializeParams: &compute.AttachedDiskInitializeParams{
					DiskName: IDiskName,
					SourceImage: "projects/centos-cloud/global/images/family/centos-7",
					DiskType:    fmt.Sprintf("projects/%s/zones/%s/diskTypes/pd-ssd", ProjectID, Zone),
					DiskSizeGb:  100,
				},
			},
		},
	}
	return computeService.Instances.Insert(ProjectID, Zone, instance).Do()
}

// startInstance is a wrapper function for the switch statement
func startInstance(cs *compute.Service, w http.ResponseWriter) {
	operation, err := StartInstance(cs)
	if err != nil {
		w.WriteHeader(http.StatusInternalServerError)
		log.Fatal(err)
	}
	w.WriteHeader(http.StatusOK)
	data, _ := operation.MarshalJSON()
	w.Write(data)
}

如果你对这个问题有任何疑问,请留下你的评论。我希望能为你提供支持。谢谢大家。

英文:

I was found my answer. Root cause is each instance must have a disk partition, with different name.
So, I change my code with some change, you can see it bellow.

package cloudfunctions

import (
	&quot;context&quot;
	&quot;fmt&quot;
	&quot;log&quot;
	&quot;net/http&quot;
	&quot;os&quot;
	&quot;google.golang.org/api/compute/v1&quot;
	&quot;time&quot;
)

var ProjectID = &quot;&quot;
var Zone = &quot;&quot;
var Region = &quot;&quot;
var InstanceName = &quot;&quot;
var InstanceType = &quot;&quot;
var IDiskName = &quot;&quot;

func DeployInstance(w http.ResponseWriter, r *http.Request) {
	ProjectID = os.Getenv(&quot;PROJECT_ID&quot;)
	Zone = os.Getenv(&quot;ZONE&quot;)
	Region = os.Getenv(&quot;REGION&quot;)

	var listInstance = []string{&quot;e2-standard-8&quot;,&quot;e2-standard-2&quot;,  &quot;n2-standard-2&quot;, &quot;n2-standard-8&quot;, &quot;n1-custom-2-8192&quot;, &quot;n1-custom-8-32768&quot;, &quot;c2-standard-8&quot;}
	for i:=0; i &lt; len(listInstance); i++ {
		cs, err := compute.NewService(context.Background())
		if err != nil {
			w.WriteHeader(http.StatusInternalServerError)
			log.Fatal(err)
		}
		InstanceType = listInstance[i]
		InstanceName = &quot;benchmark-&quot;+InstanceType
		IDiskName = InstanceName+&quot;-boot-disk&quot;

		instance, err := GetInstance(cs)
		if err != nil {
			w.WriteHeader(http.StatusTemporaryRedirect)
			w.Write([]byte(err.Error() + &quot; instance may not exist yet&quot;))

			_, err = CreateInstance(cs)
			if err != nil {
				for {
					disk, derr := cs.Disks.Get(ProjectID, Zone, IDiskName).Context(context.Background()).Do()
					log.Print(IDiskName + &quot; is &quot; + disk.Status)
					time.Sleep(1 * time.Second)
					if derr != nil {
						startInstance(cs, w)
						break
					}
				}
				
			}
		} else {
			msg := &quot;instance &quot;+ InstanceName +&quot; is in intermediate state: &quot; + instance.Status
			w.WriteHeader(http.StatusAccepted)
			w.Write([]byte(msg))
			log.Println(msg)
		}
	}
}


func GetInstance(computeService *compute.Service) (*compute.Instance, error) {
	return computeService.Instances.Get(ProjectID, Zone, InstanceName).Do()
}


func StartInstance(computeService *compute.Service) (*compute.Operation, error) {
	return computeService.Instances.Start(ProjectID, Zone, InstanceName).Do()
}

// CreateInstance creates a given instance with metadata that logs its information.
func CreateInstance(computeService *compute.Service) (*compute.Operation, error) {
	instance := &amp;compute.Instance{
		Name: InstanceName,
		MachineType: fmt.Sprintf(&quot;zones/%s/machineTypes/%s&quot;, Zone, InstanceType),
		NetworkInterfaces: []*compute.NetworkInterface{
			{
				Name:       &quot;default&quot;,
				Subnetwork: fmt.Sprintf(&quot;projects/%s/regions/%s/subnetworks/default&quot;, ProjectID, Region),
				AccessConfigs: []*compute.AccessConfig{
					{
						Name:        &quot;External NAT&quot;,
						Type:        &quot;ONE_TO_ONE_NAT&quot;,
						NetworkTier: &quot;PREMIUM&quot;,
					},
				},
			},
		},
		Scheduling: &amp;compute.Scheduling{
			Preemptible: true,
		},
		Disks: []*compute.AttachedDisk{
			{
				Boot:       true,         // The first disk must be a boot disk.
				AutoDelete: true,         //Optional
				Mode:       &quot;READ_WRITE&quot;, //Mode should be READ_WRITE or READ_ONLY
				Interface:  &quot;SCSI&quot;,       //SCSI or NVME - NVME only for SSDs
				InitializeParams: &amp;compute.AttachedDiskInitializeParams{
					DiskName: IDiskName,
					SourceImage: &quot;projects/centos-cloud/global/images/family/centos-7&quot;,
					DiskType:    fmt.Sprintf(&quot;projects/%s/zones/%s/diskTypes/pd-ssd&quot;, ProjectID, Zone),
					DiskSizeGb:  100,
				},
			},
		},
	}
	return computeService.Instances.Insert(ProjectID, Zone, instance).Do()
}

// startInstance is a wrapper function for the switch statement
func startInstance(cs *compute.Service, w http.ResponseWriter) {
	operation, err := StartInstance(cs)
	if err != nil {
		w.WriteHeader(http.StatusInternalServerError)
		log.Fatal(err)
	}
	w.WriteHeader(http.StatusOK)
	data, _ := operation.MarshalJSON()
	w.Write(data)
}

If you have any question about this problem, drop your comment. I hope I can support for you.
Thanks all.

huangapple
  • 本文由 发表于 2022年2月7日 13:25:56
  • 转载请务必保留本文链接:https://go.coder-hub.com/71013896.html
匿名

发表评论

匿名网友

:?: :razz: :sad: :evil: :!: :smile: :oops: :grin: :eek: :shock: :???: :cool: :lol: :mad: :twisted: :roll: :wink: :idea: :arrow: :neutral: :cry: :mrgreen:

确定