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
更多关于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
}
四、最佳实践
- 超时设置:总是设置合理的超时时间,避免无限等待
- 健康检查:不只是检查端口是否开放,最好实现真正的健康检查端点
- 日志记录:记录等待过程,便于故障排查
- 优雅退出:当等待超时时,确保所有资源被正确清理
- 组合使用:可以将端口检查和HTTP检查组合使用
通过结合Golang的命令行编程能力和wait-for工具,你可以构建出健壮的服务编排系统,确保服务按照正确的依赖顺序启动。