fixed issue for container not being excluded on restart

This commit is contained in:
yusing 2024-09-30 15:19:59 +08:00
parent 860e914b90
commit b38d7595a7
16 changed files with 67 additions and 52 deletions

View file

@ -27,7 +27,7 @@ logs:
docker compose logs -f docker compose logs -f
get: get:
cd cmd && go get -u && go mod tidy && cd .. go get -u ./cmd && go mod tidy
debug: debug:
make BUILD_FLAG="" build && sudo GOPROXY_DEBUG=1 bin/go-proxy make BUILD_FLAG="" build && sudo GOPROXY_DEBUG=1 bin/go-proxy

View file

@ -17,6 +17,8 @@ const (
ConfigFileName = "config.yml" ConfigFileName = "config.yml"
ConfigExampleFileName = "config.example.yml" ConfigExampleFileName = "config.example.yml"
ConfigPath = ConfigBasePath + "/" + ConfigFileName ConfigPath = ConfigBasePath + "/" + ConfigFileName
MiddlewareDefsBasePath = ConfigBasePath + "/middlewares"
) )
const ( const (

View file

@ -20,6 +20,7 @@ func FromDocker(c *types.Container, dockerHost string) (res Container) {
res.ProxyProperties = &ProxyProperties{ res.ProxyProperties = &ProxyProperties{
DockerHost: dockerHost, DockerHost: dockerHost,
ContainerName: res.getName(), ContainerName: res.getName(),
ContainerID: c.ID,
ImageName: res.getImageName(), ImageName: res.getImageName(),
PublicPortMapping: res.getPublicPortMapping(), PublicPortMapping: res.getPublicPortMapping(),
PrivatePortMapping: res.getPrivatePortMapping(), PrivatePortMapping: res.getPrivatePortMapping(),

View file

@ -63,7 +63,9 @@ func Register(entry *P.ReverseProxyEntry) (*watcher, E.NestedError) {
watcherMapMu.Lock() watcherMapMu.Lock()
defer watcherMapMu.Unlock() defer watcherMapMu.Unlock()
if w, ok := watcherMap[entry.ContainerName]; ok { key := entry.ContainerID
if w, ok := watcherMap[key]; ok {
w.refCount.Add(1) w.refCount.Add(1)
w.ReverseProxyEntry = entry w.ReverseProxyEntry = entry
return w, nil return w, nil
@ -85,7 +87,7 @@ func Register(entry *P.ReverseProxyEntry) (*watcher, E.NestedError) {
w.refCount.Add(1) w.refCount.Add(1)
w.stopByMethod = w.getStopCallback() w.stopByMethod = w.getStopCallback()
watcherMap[w.ContainerName] = w watcherMap[key] = w
go func() { go func() {
newWatcherCh <- w newWatcherCh <- w
@ -94,8 +96,8 @@ func Register(entry *P.ReverseProxyEntry) (*watcher, E.NestedError) {
return w, nil return w, nil
} }
func Unregister(containerName string) { func Unregister(entry *P.ReverseProxyEntry) {
if w, ok := watcherMap[containerName]; ok { if w, ok := watcherMap[entry.ContainerID]; ok {
w.refCount.Add(-1) w.refCount.Add(-1)
} }
} }
@ -118,7 +120,7 @@ func Start() {
w.refCount.Wait() // wait for 0 ref count w.refCount.Wait() // wait for 0 ref count
w.client.Close() w.client.Close()
delete(watcherMap, w.ContainerName) delete(watcherMap, w.ContainerID)
w.l.Debug("unregistered") w.l.Debug("unregistered")
mainLoopWg.Done() mainLoopWg.Done()
}() }()
@ -138,29 +140,29 @@ func (w *watcher) PatchRoundTripper(rtp http.RoundTripper) roundTripper {
} }
func (w *watcher) containerStop() error { func (w *watcher) containerStop() error {
return w.client.ContainerStop(w.ctx, w.ContainerName, container.StopOptions{ return w.client.ContainerStop(w.ctx, w.ContainerID, container.StopOptions{
Signal: string(w.StopSignal), Signal: string(w.StopSignal),
Timeout: &w.StopTimeout}) Timeout: &w.StopTimeout})
} }
func (w *watcher) containerPause() error { func (w *watcher) containerPause() error {
return w.client.ContainerPause(w.ctx, w.ContainerName) return w.client.ContainerPause(w.ctx, w.ContainerID)
} }
func (w *watcher) containerKill() error { func (w *watcher) containerKill() error {
return w.client.ContainerKill(w.ctx, w.ContainerName, string(w.StopSignal)) return w.client.ContainerKill(w.ctx, w.ContainerID, string(w.StopSignal))
} }
func (w *watcher) containerUnpause() error { func (w *watcher) containerUnpause() error {
return w.client.ContainerUnpause(w.ctx, w.ContainerName) return w.client.ContainerUnpause(w.ctx, w.ContainerID)
} }
func (w *watcher) containerStart() error { func (w *watcher) containerStart() error {
return w.client.ContainerStart(w.ctx, w.ContainerName, container.StartOptions{}) return w.client.ContainerStart(w.ctx, w.ContainerID, container.StartOptions{})
} }
func (w *watcher) containerStatus() (string, E.NestedError) { func (w *watcher) containerStatus() (string, E.NestedError) {
json, err := w.client.ContainerInspect(w.ctx, w.ContainerName) json, err := w.client.ContainerInspect(w.ctx, w.ContainerID)
if err != nil { if err != nil {
return "", E.FailWith("inspect container", err) return "", E.FailWith("inspect container", err)
} }
@ -219,7 +221,7 @@ func (w *watcher) watchUntilCancel() {
dockerEventCh, dockerEventErrCh := dockerWatcher.EventsWithOptions(w.ctx, W.DockerListOptions{ dockerEventCh, dockerEventErrCh := dockerWatcher.EventsWithOptions(w.ctx, W.DockerListOptions{
Filters: W.NewDockerFilter( Filters: W.NewDockerFilter(
W.DockerFilterContainer, W.DockerFilterContainer,
W.DockerrFilterContainerName(w.ContainerName), W.DockerrFilterContainer(w.ContainerID),
W.DockerFilterStart, W.DockerFilterStart,
W.DockerFilterStop, W.DockerFilterStop,
W.DockerFilterDie, W.DockerFilterDie,

View file

@ -6,6 +6,7 @@ type PortMapping = map[string]types.Port
type ProxyProperties struct { type ProxyProperties struct {
DockerHost string `yaml:"-" json:"docker_host"` DockerHost string `yaml:"-" json:"docker_host"`
ContainerName string `yaml:"-" json:"container_name"` ContainerName string `yaml:"-" json:"container_name"`
ContainerID string `yaml:"-" json:"container_id"`
ImageName string `yaml:"-" json:"image_name"` ImageName string `yaml:"-" json:"image_name"`
PublicPortMapping PortMapping `yaml:"-" json:"public_port_mapping"` // non-zero publicPort:types.Port PublicPortMapping PortMapping `yaml:"-" json:"public_port_mapping"` // non-zero publicPort:types.Port
PrivatePortMapping PortMapping `yaml:"-" json:"private_port_mapping"` // privatePort:types.Port PrivatePortMapping PortMapping `yaml:"-" json:"private_port_mapping"` // privatePort:types.Port

View file

@ -49,8 +49,6 @@ func (b Builder) Addf(format string, args ...any) Builder {
func (b Builder) Build() NestedError { func (b Builder) Build() NestedError {
if len(b.errors) == 0 { if len(b.errors) == 0 {
return nil return nil
} else if len(b.errors) == 1 {
return b.errors[0].Subjectf("%s", b.message)
} }
return Join(b.message, b.errors...) return Join(b.message, b.errors...)
} }

View file

@ -34,7 +34,7 @@ var CloudflareRealIP = &realIP{
}, },
} }
func NewCloudflareRealIP(_ OptionsRaw, _ *ReverseProxy) (*Middleware, E.NestedError) { func NewCloudflareRealIP(_ OptionsRaw) (*Middleware, E.NestedError) {
cri := new(realIP) cri := new(realIP)
cri.m = &Middleware{ cri.m = &Middleware{
impl: cri, impl: cri,

View file

@ -14,7 +14,6 @@ import (
"time" "time"
"github.com/sirupsen/logrus" "github.com/sirupsen/logrus"
"github.com/yusing/go-proxy/internal/common"
D "github.com/yusing/go-proxy/internal/docker" D "github.com/yusing/go-proxy/internal/docker"
E "github.com/yusing/go-proxy/internal/error" E "github.com/yusing/go-proxy/internal/error"
gpHTTP "github.com/yusing/go-proxy/internal/net/http" gpHTTP "github.com/yusing/go-proxy/internal/net/http"
@ -31,6 +30,7 @@ type (
TrustForwardHeader bool TrustForwardHeader bool
AuthResponseHeaders []string AuthResponseHeaders []string
AddAuthCookiesToResponse []string AddAuthCookiesToResponse []string
transport http.RoundTripper
} }
) )
@ -56,16 +56,29 @@ var ForwardAuth = func() *forwardAuth {
}() }()
var faLogger = logrus.WithField("middleware", "ForwardAuth") var faLogger = logrus.WithField("middleware", "ForwardAuth")
func NewForwardAuthfunc(optsRaw OptionsRaw, rp *ReverseProxy) (*Middleware, E.NestedError) { func NewForwardAuthfunc(optsRaw OptionsRaw) (*Middleware, E.NestedError) {
tr, ok := rp.Transport.(*http.Transport)
if ok {
tr = tr.Clone()
} else {
tr = common.DefaultTransport.Clone()
}
faWithOpts := new(forwardAuth) faWithOpts := new(forwardAuth)
faWithOpts.forwardAuthOpts = new(forwardAuthOpts) faWithOpts.forwardAuthOpts = new(forwardAuthOpts)
err := Deserialize(optsRaw, faWithOpts.forwardAuthOpts)
if err != nil {
return nil, err
}
_, err = E.Check(url.Parse(faWithOpts.Address))
if err != nil {
return nil, E.Invalid("address", faWithOpts.Address)
}
faWithOpts.m = &Middleware{
impl: faWithOpts,
before: faWithOpts.forward,
}
// TODO: use tr from reverse proxy
tr, ok := faWithOpts.forwardAuthOpts.transport.(*http.Transport)
if ok {
tr = tr.Clone()
}
faWithOpts.client = http.Client{ faWithOpts.client = http.Client{
CheckRedirect: func(r *Request, via []*Request) error { CheckRedirect: func(r *Request, via []*Request) error {
return http.ErrUseLastResponse return http.ErrUseLastResponse
@ -73,19 +86,6 @@ func NewForwardAuthfunc(optsRaw OptionsRaw, rp *ReverseProxy) (*Middleware, E.Ne
Timeout: 30 * time.Second, Timeout: 30 * time.Second,
Transport: tr, Transport: tr,
} }
faWithOpts.m = &Middleware{
impl: faWithOpts,
before: faWithOpts.forward,
}
err := Deserialize(optsRaw, faWithOpts.forwardAuthOpts)
if err != nil {
return nil, E.FailWith("set options", err)
}
_, err = E.Check(url.Parse(faWithOpts.Address))
if err != nil {
return nil, E.Invalid("address", faWithOpts.Address)
}
return faWithOpts.m, nil return faWithOpts.m, nil
} }

View file

@ -23,7 +23,7 @@ type (
BeforeFunc func(next http.Handler, w ResponseWriter, r *Request) BeforeFunc func(next http.Handler, w ResponseWriter, r *Request)
RewriteFunc func(req *Request) RewriteFunc func(req *Request)
ModifyResponseFunc func(resp *Response) error ModifyResponseFunc func(resp *Response) error
CloneWithOptFunc func(opts OptionsRaw, rp *ReverseProxy) (*Middleware, E.NestedError) CloneWithOptFunc func(opts OptionsRaw) (*Middleware, E.NestedError)
OptionsRaw = map[string]any OptionsRaw = map[string]any
Options any Options any
@ -55,7 +55,7 @@ func (m *Middleware) String() string {
func (m *Middleware) WithOptionsClone(optsRaw OptionsRaw, rp *ReverseProxy) (*Middleware, E.NestedError) { func (m *Middleware) WithOptionsClone(optsRaw OptionsRaw, rp *ReverseProxy) (*Middleware, E.NestedError) {
if len(optsRaw) != 0 && m.withOptions != nil { if len(optsRaw) != 0 && m.withOptions != nil {
if mWithOpt, err := m.withOptions(optsRaw, rp); err != nil { if mWithOpt, err := m.withOptions(optsRaw); err != nil {
return nil, err return nil, err
} else { } else {
return mWithOpt, nil return mWithOpt, nil

View file

@ -30,7 +30,7 @@ var ModifyRequest = func() *modifyRequest {
return mr return mr
}() }()
func NewModifyRequest(optsRaw OptionsRaw, _ *ReverseProxy) (*Middleware, E.NestedError) { func NewModifyRequest(optsRaw OptionsRaw) (*Middleware, E.NestedError) {
mr := new(modifyRequest) mr := new(modifyRequest)
mr.m = &Middleware{ mr.m = &Middleware{
impl: mr, impl: mr,
@ -39,7 +39,7 @@ func NewModifyRequest(optsRaw OptionsRaw, _ *ReverseProxy) (*Middleware, E.Neste
mr.modifyRequestOpts = new(modifyRequestOpts) mr.modifyRequestOpts = new(modifyRequestOpts)
err := Deserialize(optsRaw, mr.modifyRequestOpts) err := Deserialize(optsRaw, mr.modifyRequestOpts)
if err != nil { if err != nil {
return nil, E.FailWith("set options", err) return nil, err
} }
return mr.m, nil return mr.m, nil
} }

View file

@ -32,7 +32,7 @@ var ModifyResponse = func() (mr *modifyResponse) {
return return
}() }()
func NewModifyResponse(optsRaw OptionsRaw, _ *ReverseProxy) (*Middleware, E.NestedError) { func NewModifyResponse(optsRaw OptionsRaw) (*Middleware, E.NestedError) {
mr := new(modifyResponse) mr := new(modifyResponse)
mr.m = &Middleware{ mr.m = &Middleware{
impl: mr, impl: mr,
@ -41,7 +41,7 @@ func NewModifyResponse(optsRaw OptionsRaw, _ *ReverseProxy) (*Middleware, E.Nest
mr.modifyResponseOpts = new(modifyResponseOpts) mr.modifyResponseOpts = new(modifyResponseOpts)
err := Deserialize(optsRaw, mr.modifyResponseOpts) err := Deserialize(optsRaw, mr.modifyResponseOpts)
if err != nil { if err != nil {
return nil, E.FailWith("set options", err) return nil, err
} }
return mr.m, nil return mr.m, nil
} }

View file

@ -58,7 +58,7 @@ var realIPOptsDefault = func() *realIPOpts {
var realIPLogger = logrus.WithField("middleware", "RealIP") var realIPLogger = logrus.WithField("middleware", "RealIP")
func NewRealIP(opts OptionsRaw, _ *ReverseProxy) (*Middleware, E.NestedError) { func NewRealIP(opts OptionsRaw) (*Middleware, E.NestedError) {
riWithOpts := new(realIP) riWithOpts := new(realIP)
riWithOpts.m = &Middleware{ riWithOpts.m = &Middleware{
impl: riWithOpts, impl: riWithOpts,
@ -67,7 +67,7 @@ func NewRealIP(opts OptionsRaw, _ *ReverseProxy) (*Middleware, E.NestedError) {
riWithOpts.realIPOpts = realIPOptsDefault() riWithOpts.realIPOpts = realIPOptsDefault()
err := Deserialize(opts, riWithOpts.realIPOpts) err := Deserialize(opts, riWithOpts.realIPOpts)
if err != nil { if err != nil {
return nil, E.FailWith("set options", err) return nil, err
} }
return riWithOpts.m, nil return riWithOpts.m, nil
} }

View file

@ -28,6 +28,7 @@ type (
StopSignal T.Signal StopSignal T.Signal
DockerHost string DockerHost string
ContainerName string ContainerName string
ContainerID string
ContainerRunning bool ContainerRunning bool
} }
StreamEntry struct { StreamEntry struct {
@ -115,6 +116,7 @@ func validateRPEntry(m *M.RawEntry, s T.Scheme, b E.Builder) *ReverseProxyEntry
StopSignal: stopSignal, StopSignal: stopSignal,
DockerHost: m.DockerHost, DockerHost: m.DockerHost,
ContainerName: m.ContainerName, ContainerName: m.ContainerName,
ContainerID: m.ContainerID,
ContainerRunning: m.Running, ContainerRunning: m.Running,
} }
} }

View file

@ -78,12 +78,17 @@ func (p *DockerProvider) LoadRoutesImpl() (routes R.Routes, err E.NestedError) {
return routes, errors.Build() return routes, errors.Build()
} }
func (p *DockerProvider) shouldIgnore(container D.Container) bool {
return container.IsExcluded ||
!container.IsExplicit && p.ExplicitOnly
}
func (p *DockerProvider) OnEvent(event W.Event, routes R.Routes) (res EventResult) { func (p *DockerProvider) OnEvent(event W.Event, routes R.Routes) (res EventResult) {
b := E.NewBuilder("event %s error", event) b := E.NewBuilder("event %s error", event)
defer b.To(&res.err) defer b.To(&res.err)
routes.RangeAll(func(k string, v R.Route) { routes.RangeAll(func(k string, v R.Route) {
if v.Entry().ContainerName == event.ActorName { if v.Entry().ContainerID == event.ActorID {
b.Add(v.Stop()) b.Add(v.Stop())
routes.Delete(k) routes.Delete(k)
res.nRemoved++ res.nRemoved++
@ -101,6 +106,11 @@ func (p *DockerProvider) OnEvent(event W.Event, routes R.Routes) (res EventResul
b.Add(E.FailWith("inspect container", err)) b.Add(E.FailWith("inspect container", err))
return return
} }
if p.shouldIgnore(cont) {
return
}
entries, err := p.entriesFromContainerLabels(cont) entries, err := p.entriesFromContainerLabels(cont)
b.Add(err) b.Add(err)
@ -126,8 +136,7 @@ func (p *DockerProvider) OnEvent(event W.Event, routes R.Routes) (res EventResul
func (p *DockerProvider) entriesFromContainerLabels(container D.Container) (entries M.RawEntries, _ E.NestedError) { func (p *DockerProvider) entriesFromContainerLabels(container D.Container) (entries M.RawEntries, _ E.NestedError) {
entries = M.NewProxyEntries() entries = M.NewProxyEntries()
if container.IsExcluded || if p.shouldIgnore(container) {
!container.IsExplicit && p.ExplicitOnly {
return return
} }

View file

@ -89,7 +89,7 @@ func NewHTTPRoute(entry *P.ReverseProxyEntry) (*HTTPRoute, E.NestedError) {
return nil return nil
} }
unregIdleWatcher = func() { unregIdleWatcher = func() {
idlewatcher.Unregister(entry.ContainerName) idlewatcher.Unregister(entry)
rp.Transport = trans rp.Transport = trans
} }
} }

View file

@ -37,8 +37,8 @@ var (
dockerWatcherRetryInterval = 3 * time.Second dockerWatcherRetryInterval = 3 * time.Second
) )
func DockerrFilterContainerName(name string) filters.KeyValuePair { func DockerrFilterContainer(nameOrID string) filters.KeyValuePair {
return filters.Arg("container", name) return filters.Arg("container", nameOrID)
} }
func NewDockerWatcher(host string) DockerWatcher { func NewDockerWatcher(host string) DockerWatcher {