golang与Mesosphere Marathon PAAS交互的插件库go-marathon的使用

Golang与Mesosphere Marathon PAAS交互的插件库go-marathon的使用

概述

go-marathon是一个用于与Marathon交互的API库,支持以下功能:

  • 应用程序和组部署
  • 用于获取状态、配置和任务的辅助过滤器
  • 支持HA部署的多个端点
  • Marathon事件订阅和事件流
  • Pods

注意:该库仍在积极开发中,用户应预期API可能会有频繁变化(包括破坏性变更)。要求Go 1.6或更高版本。

代码示例

创建客户端

import (
	marathon "github.com/gambol99/go-marathon"
)

marathonURL := "http://10.241.1.71:8080"
config := marathon.NewDefaultConfig()
config.URL = marathonURL
client, err := marathon.NewClient(config)
if err != nil {
	log.Fatalf("Failed to create a client for marathon, error: %s", err)
}

applications, err := client.Applications(nil)
...

可以指定多个Marathon端点(例如在HA模式下运行Marathon时):

marathonURL := "http://10.241.1.71:8080,10.241.1.72:8080,10.241.1.73:8080"

自定义HTTP客户端

可以传递自定义HTTP客户端以自定义行为(例如绕过TLS验证、加载根CA或更改超时):

marathonURL := "http://10.241.1.71:8080"
config := marathon.NewDefaultConfig()
config.URL = marathonURL
config.HTTPClient = &http.Client{
    Timeout: (time.Duration(10) * time.Second),
    Transport: &http.Transport{
        Dial: (&net.Dialer{
            Timeout:   10 * time.Second,
            KeepAlive: 10 * time.Second,
        }).Dial,
        TLSClientConfig: &tls.Config{
            InsecureSkipVerify: true,
        },
    },
}
config.HTTPSSEClient = &http.Client{
    // 不能设置Timeout,因为它包含读取响应体的超时
    Transport: &http.Transport{
        Dial: (&net.Dialer{
            Timeout:   10 * time.Second,
            KeepAlive: 10 * time.Second,
        }).Dial,
        TLSClientConfig: &tls.Config{
            InsecureSkipVerify: true,
        },
    },
}

列出应用程序

applications, err := client.Applications(nil)
if err != nil {
	log.Fatalf("Failed to list applications: %s", err)
}

log.Printf("Found %d application(s) running", len(applications.Apps))
for _, application := range applications.Apps {
	log.Printf("Application: %s", application)
	appID := application.ID

	details, err := client.Application(appID)
	if err != nil {
		log.Fatalf("Failed to get application %s: %s", appID, err)
	}
	if details.Tasks != nil {
		for _, task := range details.Tasks {
			log.Printf("application %s has task: %s", appID, task)
		}
	}
}

创建新应用程序

log.Printf("Deploying a new application")
application := marathon.NewDockerApplication().
  Name(applicationName).
  CPU(0.1).
  Memory(64).
  Storage(0.0).
  Count(2).
  AddArgs("/usr/sbin/apache2ctl", "-D", "FOREGROUND").
  AddEnv("NAME", "frontend_http").
  AddEnv("SERVICE_80_NAME", "test_http").
  CheckHTTP("/health", 10, 5)

application.
  Container.Docker.Container("quay.io/gambol99/apache-php:latest").
  Bridged().
  Expose(80).
  Expose(443)

if _, err := client.CreateApplication(application); err != nil {
	log.Fatalf("Failed to create application: %s, error: %s", application, err)
} else {
	log.Printf("Created the application: %s", application)
}

扩展应用程序

将应用程序实例数更改为4:

log.Printf("Scale to 4 instances")
if err := client.ScaleApplicationInstances(application.ID, 4); err != nil {
	log.Fatalf("Failed to delete the application: %s, error: %s", application, err)
} else {
	client.WaitOnApplication(application.ID, 30 * time.Second)
	log.Printf("Successfully scaled the application")
}

Pods

Pods允许您将任务组作为单元部署。Pod中所有任务共享网络和存储:

// 初始化运行nginx的单容器pod
pod := marathon.NewPod()

image := marathon.NewDockerPodContainerImage().SetID("nginx")

container := marathon.NewPodContainer().
	SetName("container", i).
	CPUs(0.1).
	Memory(128).
	SetImage(image)

pod.Name("mypod").AddContainer(container)

// 创建并等待启动
pod, err := client.CreatePod(pod)
err = client.WaitOnPod(pod.ID, time.Minute*1)

// 扩展
pod.Count(5)
pod, err = client.UpdatePod(pod, true)

// 删除
id, err := client.DeletePod(pod.ID, true)

订阅和事件

事件流

仅适用于Marathon >= 0.9.0,不需要特殊配置:

// 配置客户端
config := marathon.NewDefaultConfig()
config.URL = marathonURL
config.EventsTransport = marathon.EventsTransportSSE

client, err := marathon.NewClient(config)
if err != nil {
	log.Fatalf("Failed to create a client for marathon, error: %s", err)
}

// 注册事件监听
events, err = client.AddEventsListener(marathon.EventIDApplications)
if err != nil {
	log.Fatalf("Failed to register for events, %s", err)
}

timer := time.After(60 * time.Second)
done := false

// 从通道接收事件60秒
for {
	if done {
		break
	}
	select {
	case <-timer:
		log.Printf("Exiting the loop")
		done = true
	case event := <-events:
		log.Printf("Received event: %s", event)
	}
}

// 取消订阅Marathon事件
client.RemoveEventsListener(events)

事件订阅

需要启动内置Web服务器:

// 配置客户端
config := marathon.NewDefaultConfig()
config.URL = marathonURL
config.EventsInterface = marathonInterface
config.EventsPort = marathonPort

client, err := marathon.NewClient(config)
if err != nil {
	log.Fatalf("Failed to create a client for marathon, error: %s", err)
}

// 注册事件监听
events, err = client.AddEventsListener(marathon.EventIDApplications)
if err != nil {
	log.Fatalf("Failed to register for events, %s", err)
}

timer := time.After(60 * time.Second)
done := false

// 从通道接收事件60秒
for {
	if done {
		break
	}
	select {
	case <-timer:
		log.Printf("Exiting the loop")
		done = true
	case event := <-events:
		log.Printf("Received event: %s", event)
	}
}

// 取消订阅Marathon事件
client.RemoveEventsListener(events)

控制订阅

// 配置客户端
config := marathon.NewDefaultConfig()
config.URL = marathonURL

client, err := marathon.NewClient(config)
if err != nil {
	log.Fatalf("Failed to create a client for marathon, error: %s", err)
}

// 通过回调URL注册事件订阅者
callbackURL := "http://10.241.1.71:9494"
if err := client.Subscribe(callbackURL); err != nil {
	log.Fatalf("Unable to register the callbackURL [%s], error: %s", callbackURL, err)
}

// 注销同一订阅者
if err := client.Unsubscribe(callbackURL); err != nil {
	log.Fatalf("Unable to deregister the callbackURL [%s], error: %s", callbackURL, err)
}

更多关于golang与Mesosphere Marathon PAAS交互的插件库go-marathon的使用的实战教程也可以访问 https://www.itying.com/category-94-b0.html

1 回复

更多关于golang与Mesosphere Marathon PAAS交互的插件库go-marathon的使用的实战系列教程也可以访问 https://www.itying.com/category-94-b0.html


使用go-marathon与Mesosphere Marathon交互

go-marathon是一个用于与Mesosphere Marathon平台交互的Golang客户端库。下面我将介绍如何使用这个库来管理Marathon应用。

安装

首先安装go-marathon库:

go get github.com/gambol99/go-marathon

基本使用

1. 创建客户端

package main

import (
	"fmt"
	"log"
	"time"

	marathon "github.com/gambol99/go-marathon"
)

func main() {
	config := marathon.NewDefaultConfig()
	config.URL = "http://marathon.example.com:8080" // Marathon服务器地址
	config.HTTPClient = &http.Client{
		Timeout: 10 * time.Second,
	}

	client, err := marathon.NewClient(config)
	if err != nil {
		log.Fatalf("Failed to create Marathon client: %v", err)
	}
	
	// 使用client进行后续操作
}

2. 创建应用

func createApp(client marathon.Marathon) {
	app := &marathon.Application{
		ID: "/my-app",
		CPUs: 0.5,
		Mem:  128.0,
		Disk: 0.0,
		Instances: 1,
		Container: &marathon.Container{
			Type: "DOCKER",
			Docker: &marathon.Docker{
				Image: "nginx:latest",
				Network: "BRIDGE",
				PortMappings: []*marathon.PortMapping{
					{
						ContainerPort: 80,
						HostPort:      0, // 0表示让Marathon自动分配
						Protocol:      "tcp",
					},
				},
			},
		},
	}

	_, err := client.CreateApplication(app, false)
	if err != nil {
		log.Printf("Failed to create application: %v", err)
		return
	}
	
	log.Println("Application created successfully")
}

3. 列出所有应用

func listApps(client marathon.Marathon) {
	applications, err := client.Applications(nil)
	if err != nil {
		log.Printf("Failed to fetch applications: %v", err)
		return
	}

	for _, app := range applications.Apps {
		fmt.Printf("ID: %s, Instances: %d, CPU: %.2f, Memory: %.2f\n",
			app.ID, app.Instances, app.CPUs, app.Mem)
	}
}

4. 扩展应用实例

func scaleApp(client marathon.Marathon, appID string, instances int) {
	_, err := client.ScaleApplicationInstances(appID, instances, false)
	if err != nil {
		log.Printf("Failed to scale application: %v", err)
		return
	}
	
	log.Printf("Application %s scaled to %d instances", appID, instances)
}

5. 更新应用

func updateApp(client marathon.Marathon, appID string) {
	// 首先获取当前应用配置
	app, err := client.Application(appID)
	if err != nil {
		log.Printf("Failed to get application: %v", err)
		return
	}

	// 修改配置
	app.CPUs = 1.0
	app.Mem = 256.0
	app.Instances = 2

	// 更新应用
	_, err = client.UpdateApplication(app, false)
	if err != nil {
		log.Printf("Failed to update application: %v", err)
		return
	}
	
	log.Printf("Application %s updated successfully", appID)
}

6. 删除应用

func deleteApp(client marathon.Marathon, appID string) {
	_, err := client.DeleteApplication(appID, false)
	if err != nil {
		log.Printf("Failed to delete application: %v", err)
		return
	}
	
	log.Printf("Application %s deleted successfully", appID)
}

高级功能

1. 使用健康检查

func createAppWithHealthCheck(client marathon.Marathon) {
	app := &marathon.Application{
		ID: "/health-check-app",
		CPUs: 0.5,
		Mem:  128.0,
		Instances: 1,
		Container: &marathon.Container{
			Type: "DOCKER",
			Docker: &marathon.Docker{
				Image: "nginx:latest",
				Network: "BRIDGE",
				PortMappings: []*marathon.PortMapping{
					{ContainerPort: 80, HostPort: 0, Protocol: "tcp"},
				},
			},
		},
		HealthChecks: []*marathon.HealthCheck{
			{
				Protocol:               "HTTP",
				Path:                   "/",
				PortIndex:              0,
				GracePeriodSeconds:     30,
				IntervalSeconds:       10,
				TimeoutSeconds:        5,
				MaxConsecutiveFailures: 3,
			},
		},
	}

	_, err := client.CreateApplication(app, false)
	if err != nil {
		log.Printf("Failed to create application with health check: %v", err)
		return
	}
	
	log.Println("Application with health check created successfully")
}

2. 使用环境变量和标签

func createAppWithEnvAndLabels(client marathon.Marathon) {
	app := &marathon.Application{
		ID: "/env-label-app",
		CPUs: 0.5,
		Mem:  128.0,
		Instances: 1,
		Container: &marathon.Container{
			Type: "DOCKER",
			Docker: &marathon.Docker{
				Image: "nginx:latest",
				Network: "BRIDGE",
			},
		},
		Env: map[string]string{
			"ENV_VAR1": "value1",
			"ENV_VAR2": "value2",
		},
		Labels: map[string]string{
			"owner": "dev-team",
			"env":   "production",
		},
	}

	_, err := client.CreateApplication(app, false)
	if err != nil {
		log.Printf("Failed to create application with env and labels: %v", err)
		return
	}
	
	log.Println("Application with environment variables and labels created successfully")
}

错误处理

go-marathon返回的错误通常包含详细的API错误信息:

func handleError(err error) {
	if apiErr, ok := err.(*marathon.APIError); ok {
		log.Printf("Marathon API error: %d - %s", apiErr.Code, apiErr.Message)
		if apiErr.Details != nil {
			for _, detail := range apiErr.Details {
				log.Printf("Detail: %s", detail)
			}
		}
	} else {
		log.Printf("Error: %v", err)
	}
}

总结

go-marathon库提供了全面的功能来与Marathon交互,包括:

  1. 应用生命周期管理(创建、更新、删除)
  2. 应用扩展和部署
  3. 健康检查配置
  4. 环境变量和标签管理
  5. 错误处理和调试

通过这个库,你可以轻松地将Marathon集成到你的Golang应用中,实现自动化的容器编排管理。

回到顶部