diff --git a/internal/route/http.go b/internal/route/http.go index f98d1571..c6ffce5d 100755 --- a/internal/route/http.go +++ b/internal/route/http.go @@ -5,6 +5,7 @@ import ( "github.com/rs/zerolog" "github.com/yusing/go-proxy/internal/common" + "github.com/yusing/go-proxy/internal/docker" "github.com/yusing/go-proxy/internal/docker/idlewatcher" E "github.com/yusing/go-proxy/internal/error" gphttp "github.com/yusing/go-proxy/internal/net/http" @@ -92,7 +93,16 @@ func (r *HTTPRoute) Start(providerSubtask task.Task) E.Error { r.handler = waker r.HealthMon = waker case entry.UseHealthCheck(r): - r.HealthMon = monitor.NewHTTPHealthMonitor(r.rp.TargetURL, r.HealthCheck) + if entry.IsDocker(r) { + client, err := docker.ConnectClient(r.Idlewatcher.DockerHost) + if err == nil { + fallback := monitor.NewHTTPHealthChecker(r.rp.TargetURL, r.HealthCheck) + r.HealthMon = monitor.NewDockerHealthMonitor(client, r.Idlewatcher.ContainerID, r.HealthCheck, fallback) + } + } + if r.HealthMon == nil { + r.HealthMon = monitor.NewHTTPHealthMonitor(r.rp.TargetURL, r.HealthCheck) + } } if r.handler == nil { diff --git a/internal/route/stream.go b/internal/route/stream.go index da87b6b7..4031c3e4 100755 --- a/internal/route/stream.go +++ b/internal/route/stream.go @@ -6,6 +6,7 @@ import ( "fmt" "github.com/rs/zerolog" + "github.com/yusing/go-proxy/internal/docker" "github.com/yusing/go-proxy/internal/docker/idlewatcher" E "github.com/yusing/go-proxy/internal/error" net "github.com/yusing/go-proxy/internal/net/types" @@ -67,7 +68,16 @@ func (r *StreamRoute) Start(providerSubtask task.Task) E.Error { r.Stream = waker r.HealthMon = waker case entry.UseHealthCheck(r): - r.HealthMon = monitor.NewRawHealthMonitor(r.TargetURL(), r.HealthCheck) + if entry.IsDocker(r) { + client, err := docker.ConnectClient(r.Idlewatcher.DockerHost) + if err == nil { + fallback := monitor.NewRawHealthChecker(r.TargetURL(), r.HealthCheck) + r.HealthMon = monitor.NewDockerHealthMonitor(client, r.Idlewatcher.ContainerID, r.HealthCheck, fallback) + } + } + if r.HealthMon == nil { + r.HealthMon = monitor.NewRawHealthMonitor(r.TargetURL(), r.HealthCheck) + } } if err := r.Stream.Setup(); err != nil { diff --git a/internal/watcher/health/monitor/docker.go b/internal/watcher/health/monitor/docker.go new file mode 100644 index 00000000..3d758f9d --- /dev/null +++ b/internal/watcher/health/monitor/docker.go @@ -0,0 +1,51 @@ +package monitor + +import ( + "bytes" + + "github.com/yusing/go-proxy/internal/docker" + "github.com/yusing/go-proxy/internal/net/types" + + dockerTypes "github.com/docker/docker/api/types" + "github.com/yusing/go-proxy/internal/watcher/health" +) + +type DockerHealthMonitor struct { + *monitor + client *docker.SharedClient + containerID string + fallback health.HealthChecker +} + +func NewDockerHealthMonitor(client *docker.SharedClient, containerID string, config *health.HealthCheckConfig, fallback health.HealthChecker) *DockerHealthMonitor { + mon := new(DockerHealthMonitor) + mon.client = client + mon.containerID = containerID + mon.monitor = newMonitor(types.URL{}, config, mon.CheckHealth) + mon.fallback = fallback + return mon +} + +func (mon *DockerHealthMonitor) CheckHealth() (result *health.HealthCheckResult, err error) { + cont, err := mon.client.ContainerInspect(mon.task.Context(), mon.containerID) + if err != nil { + return mon.fallback.CheckHealth() + } + if cont.State.Health == nil { + return mon.fallback.CheckHealth() + } + result = new(health.HealthCheckResult) + result.Healthy = cont.State.Health.Status == dockerTypes.Healthy + detail := new(bytes.Buffer) + for _, status := range cont.State.Health.Log { + detail.WriteString(status.Output) + detail.WriteString("\n") + } + result.Detail = detail.String() + if len(cont.State.Health.Log) > 0 { + last := cont.State.Health.Log[len(cont.State.Health.Log)-1].End + first := cont.State.Health.Log[0].Start + result.Latency = last.Sub(first) + } + return +}