golang命令行服务编排与Docker等待工具插件wait-for的使用

Golang命令行服务编排与Docker等待工具插件wait-for的使用

wait-for简介

wait-for是一个CLI工具,用于在继续执行前等待某个事件发生。它跨平台运行,可以作为单一依赖项下载到容器或环境中。

通常用于等待其他资源(如HTTP资源)变为可用状态后再继续执行,或者超时退出并报错。目前支持等待以下几种类型:

  • HTTP或HTTPS成功响应,或符合正则表达式预期的任何响应
  • TCP或GRPC连接
  • DNS IP地址解析变更

安装wait-for

使用go命令安装

go install github.com/dnnrly/wait-for/cmd/wait-for@latest

在Docker容器中安装

如果没有安装Go(例如在Docker容器中),可以使用预编译版本:

wget https://github.com/dnnrly/wait-for/releases/download/v0.0.5/wait-for_0.0.5_linux_386.tar.gz
gunzip wait-for_0.0.5_linux_386.tar.gz
tar -xfv wait-for_0.0.5_linux_386.tar

或在Dockerfile中:

ADD https://github.com/dnnrly/wait-for/releases/download/v0.0.1/wait-for_0.0.5_linux_386.tar.gz wait-for.tar.gz
RUN gunzip wait-for.tar.gz && tar -xf wait-for.tar

使用wait-for

等待任意HTTP服务

$ wait-for http://your-service-here:8080/health https://another-service/

等待具有预期响应状态的HTTP服务

$ wait-for -status=[0-2]{3} http://your-service-here:8080/health

等待gRPC服务

$ wait-for grpc-server:8092 other-grpc-server:9091

等待DNS变更

$ wait-for dns:google.com

这将等待与该DNS名称绑定的IP地址列表更新(不考虑顺序)。可用于等待DNS更新,如故障转移等操作。

预配置要连接的服务

$ wait-for preconfigured-service

默认情况下,wait-for会在当前目录中查找名为.wait-for.yml的文件。在其中可以定义要等待的服务名称。

示例.wait-for.yml配置:

wait-for:
  preconfigured-service:
    type: http
    target: http://the-service:8080/health?reload=true
    interval: 5s
    timeout: 60s
    http-client-timeout: 3s
  another-service:
    type: http
    target: https://another-one
  grpcService:
    type: grpc
    target: localhost:9092
  snmp-service:
    type: tcp
    target: snmp-trap-dns:514
  dns-thing:
    type: dns
    target: your.r53-entry.com

在Docker Compose中使用wait-for

可以在compose文件中使用wait-for进行编排。示例如下:

version: '3'
services:
  web:
    build: .
    ports:
      - "8080"
    command: sh -c 'wait-for tcp:db:5432 && ./your-api
    depends_on:
      - db
  db:
    image: "postgres:13-alpine"
    command: "-c log_statement=all"
    environment:
      POSTGRES_DB: weallvote-api
      POSTGRES_USER: ${POSTGRES_USER:-postgres}
      POSTGRES_PASSWORD: ${POSTGRES_PASSWORD:-postgres}

开发wait-for

构建工具

要构建工具以便本地运行,可以使用以下命令:

$ make build

单元测试

可以像构建系统那样运行测试:

$ make test

或以Go常规方式运行测试:

$ go test ./...

验收测试

有一套GoDog测试来检查构建的工具是否符合预期:

$ make acceptance-test

如果系统设置不允许打开必要的端口来运行验收测试,可以在Docker中运行这些测试:

$ make acceptance-test-docker

更多关于golang命令行服务编排与Docker等待工具插件wait-for的使用的实战教程也可以访问 https://www.itying.com/category-94-b0.html

1 回复

更多关于golang命令行服务编排与Docker等待工具插件wait-for的使用的实战系列教程也可以访问 https://www.itying.com/category-94-b0.html


Golang命令行服务编排与Docker wait-for工具使用指南

在微服务架构和容器化部署中,服务之间的依赖关系和启动顺序管理是一个常见挑战。本文将介绍如何使用Golang进行命令行服务编排,并结合Docker生态中的wait-for工具来确保服务依赖关系。

一、Golang命令行服务编排

Golang提供了强大的标准库来构建命令行工具和服务编排逻辑。以下是一个基本的服务编排示例:

package main

import (
	"fmt"
	"log"
	"os/exec"
	"sync"
)

func main() {
	services := []struct {
		name     string
		command  string
		args     []string
		dependsOn []string
	}{
		{"database", "docker", []string{"run", "-d", "--name=db", "postgres"}, nil},
		{"redis", "docker", []string{"run", "-d", "--name=redis", "redis"}, nil},
		{"app", "docker", []string{"run", "--name=app", "--link=db", "--link=redis", "myapp"}, []string{"database", "redis"}},
	}

	var wg sync.WaitGroup
	serviceStatus := make(map[string]bool)

	for _, svc := range services {
		wg.Add(1)
		go func(svc struct {
			name     string
			command  string
			args     []string
			dependsOn []string
		}) {
			defer wg.Done()

			// 检查依赖
			for _, dep := range svc.dependsOn {
				for !serviceStatus[dep] {
					// 等待依赖服务就绪
				}
			}

			cmd := exec.Command(svc.command, svc.args...)
			output, err := cmd.CombinedOutput()
			if err != nil {
				log.Printf("Failed to start %s: %v\nOutput: %s", svc.name, err, output)
				return
			}
			fmt.Printf("Service %s started successfully\n", svc.name)
			serviceStatus[svc.name] = true
		}(svc)
	}

	wg.Wait()
	fmt.Println("All services started")
}

二、Docker wait-for工具的使用

wait-for是一个常用的等待工具,可以检查TCP端口或HTTP端点是否就绪。以下是几种使用方式:

1. 使用官方wait-for脚本

FROM golang:1.21 as builder
WORKDIR /app
COPY . .
RUN go build -o myapp

FROM alpine:3.14
WORKDIR /app
COPY --from=builder /app/myapp .
COPY wait-for.sh .
RUN chmod +x wait-for.sh

CMD ["./wait-for.sh", "db:5432", "--", "./myapp"]

2. Golang实现的wait-for替代方案

如果你不想依赖外部脚本,可以用纯Golang实现:

package main

import (
	"fmt"
	"net"
	"os"
	"time"
)

func waitFor(host string, port string, timeout time.Duration) bool {
	start := time.Now()
	for time.Since(start) < timeout {
		conn, err := net.Dial("tcp", fmt.Sprintf("%s:%s", host, port))
		if err == nil {
			conn.Close()
			return true
		}
		time.Sleep(1 * time.Second)
	}
	return false
}

func main() {
	if len(os.Args) < 3 {
		fmt.Println("Usage: wait-for <host> <port> [timeout] [-- command args...]")
		os.Exit(1)
	}

	host := os.Args[1]
	port := os.Args[2]
	timeout := 30 * time.Second

	// 解析超时参数
	args := os.Args[3:]
	var command []string
	for i, arg := range args {
		if arg == "--" {
			command = args[i+1:]
			args = args[:i]
			break
		}
	}

	// 检查服务是否就绪
	if !waitFor(host, port, timeout) {
		fmt.Printf("Timeout waiting for %s:%s\n", host, port)
		os.Exit(1)
	}

	// 执行后续命令
	if len(command) > 0 {
		cmd := exec.Command(command[0], command[1:]...)
		cmd.Stdout = os.Stdout
		cmd.Stderr = os.Stderr
		if err := cmd.Run(); err != nil {
			os.Exit(1)
		}
	}
}

3. 在Docker Compose中使用

version: '3.8'

services:
  db:
    image: postgres
    environment:
      POSTGRES_PASSWORD: example

  app:
    build: .
    depends_on:
      - db
    command: ["./wait-for", "db:5432", "--", "./myapp"]

三、高级用法:HTTP端点检查

对于HTTP服务,可以扩展wait-for功能:

func waitForHTTP(url string, timeout time.Duration, expectedStatus int) bool {
	client := http.Client{Timeout: 1 * time.Second}
	start := time.Now()
	
	for time.Since(start) < timeout {
		resp, err := client.Get(url)
		if err == nil && resp.StatusCode == expectedStatus {
			resp.Body.Close()
			return true
		}
		if resp != nil {
			resp.Body.Close()
		}
		time.Sleep(1 * time.Second)
	}
	return false
}

四、最佳实践

  1. 超时设置:总是设置合理的超时时间,避免无限等待
  2. 健康检查:不只是检查端口是否开放,最好实现真正的健康检查端点
  3. 日志记录:记录等待过程,便于故障排查
  4. 优雅退出:当等待超时时,确保所有资源被正确清理
  5. 组合使用:可以将端口检查和HTTP检查组合使用

通过结合Golang的命令行编程能力和wait-for工具,你可以构建出健壮的服务编排系统,确保服务按照正确的依赖顺序启动。

回到顶部