11package caddydockerproxy
22
33import (
4+ "encoding/json"
45 "flag"
6+ "io/ioutil"
57 "net"
8+ "net/http"
9+ "net/url"
610 "os"
711 "regexp"
812 "strings"
@@ -31,35 +35,50 @@ func init() {
3135 "Which mode this instance should run: standalone | controller | server" )
3236
3337 fs .String ("docker-sockets" , "" ,
34- "Docker sockets comma separate" )
38+ "Docker sockets comma separate.\n " +
39+ "Applicable to modes: controller, standalone" )
3540
3641 fs .String ("docker-certs-path" , "" ,
37- "Docker socket certs path comma separate" )
42+ "Docker socket certs path comma separate.\n " +
43+ "Applicable to modes: controller, standalone" )
3844
3945 fs .String ("docker-apis-version" , "" ,
40- "Docker socket apis version comma separate" )
46+ "Docker socket apis version comma separate.\n " +
47+ "Applicable to modes: controller, standalone" )
4148
4249 fs .String ("controller-network" , "" ,
43- "Network allowed to configure caddy server in CIDR notation. Ex: 10.200.200.0/24" )
50+ "Controller network name. Ex: caddy_controller.\n " +
51+ "When not defined, all networks attached to controller container are considered controller networks\n " +
52+ "Applicable to modes: controller, standalone" )
53+
54+ fs .String ("controller-url" , "" ,
55+ "Controller url, used by servers to fetch controller subnets. Ex: http://caddy-controller\n " +
56+ "Applicable to modes: server" )
4457
4558 fs .String ("ingress-networks" , "" ,
4659 "Comma separated name of ingress networks connecting caddy servers to containers.\n " +
47- "When not defined, networks attached to controller container are considered ingress networks" )
60+ "When not defined, all networks attached to controller container are considered ingress networks\n " +
61+ "Applicable to modes: controller, standalone" )
4862
4963 fs .String ("caddyfile-path" , "" ,
50- "Path to a base Caddyfile that will be extended with docker sites" )
64+ "Path to a base Caddyfile that will be extended with docker sites.\n " +
65+ "Applicable to modes: controller, standalone" )
5166
5267 fs .String ("label-prefix" , generator .DefaultLabelPrefix ,
53- "Prefix for Docker labels" )
68+ "Prefix for Docker labels.\n " +
69+ "Applicable to modes: controller, standalone" )
5470
5571 fs .Bool ("proxy-service-tasks" , true ,
56- "Proxy to service tasks instead of service load balancer" )
72+ "Proxy to service tasks instead of service load balancer.\n " +
73+ "Applicable to modes: controller, standalone" )
5774
5875 fs .Bool ("process-caddyfile" , true ,
59- "Process Caddyfile before loading it, removing invalid servers" )
76+ "Process Caddyfile before loading it, removing invalid servers.\n " +
77+ "Applicable to modes: controller, standalone" )
6078
6179 fs .Duration ("polling-interval" , 30 * time .Second ,
62- "Interval caddy should manually check docker for a new caddyfile" )
80+ "Interval caddy should manually check docker for a new caddyfile.\n " +
81+ "Applicable to modes: controller, standalone" )
6382
6483 return fs
6584 }(),
@@ -75,9 +94,14 @@ func cmdFunc(flags caddycmd.Flags) (int, error) {
7594 if options .Mode & config .Server == config .Server {
7695 log .Info ("Running caddy proxy server" )
7796
78- err := caddy .Run (& caddy.Config {
97+ bindAddress , err := getAdminListen (options )
98+ if err != nil {
99+ return 1 , err
100+ }
101+
102+ err = caddy .Run (& caddy.Config {
79103 Admin : & caddy.AdminConfig {
80- Listen : getAdminListen ( options ) ,
104+ Listen : bindAddress ,
81105 },
82106 })
83107 if err != nil {
@@ -87,8 +111,8 @@ func cmdFunc(flags caddycmd.Flags) (int, error) {
87111
88112 if options .Mode & config .Controller == config .Controller {
89113 log .Info ("Running caddy proxy controller" )
90- loader := CreateDockerLoader (options )
91- if err := loader .Start (); err != nil {
114+ controller := CreateCaddyController (options )
115+ if err := controller .Start (); err != nil {
92116 if err := caddy .Stop (); err != nil {
93117 return 1 , err
94118 }
@@ -100,37 +124,72 @@ func cmdFunc(flags caddycmd.Flags) (int, error) {
100124 select {}
101125}
102126
103- func getAdminListen (options * config.Options ) string {
104- if options .ControllerNetwork != nil {
105- ifaces , err := net .Interfaces ()
106- log := logger ()
127+ func getAdminListen (options * config.Options ) (string , error ) {
128+ if options .Mode & config .Controller == config .Controller {
129+ return "tcp/localhost:2019" , nil
130+ }
131+
132+ log := logger ()
133+
134+ var controllerNetworks []string
135+
136+ if options .ControllerNetwork != "" {
137+ controllerNetworks = append (controllerNetworks , options .ControllerNetwork )
138+ }
107139
140+ if options .ControllerUrl != nil {
141+ url := strings .TrimRight (options .ControllerUrl .String (), "/" ) + "/controller-subnets"
142+ log .Info ("Fetching controller networks from url" , zap .String ("url" , url ))
143+ resp , err := http .Get (url )
108144 if err != nil {
109- log .Error ("Failed to get network interfaces" , zap .Error (err ))
145+ log .Error ("Failed to fetch controller networks from contoller" , zap .String ("url" , url ), zap .Error (err ))
146+ return "" , err
110147 }
111- for _ , i := range ifaces {
112- addrs , err := i .Addrs ()
113- if err != nil {
114- log .Error ("Failed to get network interface addresses" , zap .Error (err ))
115- continue
116- }
117- for _ , a := range addrs {
118- switch v := a .(type ) {
148+ body , err := ioutil .ReadAll (resp .Body )
149+ if err != nil {
150+ return "" , err
151+ }
152+ json .Unmarshal (body , & controllerNetworks )
153+ }
154+
155+ var ipNets []* net.IPNet
156+ for _ , controllerNetwork := range controllerNetworks {
157+ _ , ipNet , err := net .ParseCIDR (controllerNetwork )
158+ if err != nil {
159+ log .Error ("Failed to parse controller network" , zap .String ("ControllerNetwork" , controllerNetwork ), zap .Error (err ))
160+ return "" , err
161+ }
162+ ipNets = append (ipNets , ipNet )
163+ }
164+
165+ ifaces , err := net .Interfaces ()
166+ if err != nil {
167+ log .Error ("Failed to get network interfaces" , zap .Error (err ))
168+ return "" , err
169+ }
170+ for _ , iface := range ifaces {
171+ addrs , err := iface .Addrs ()
172+ if err != nil {
173+ log .Error ("Failed to get network interface addresses" , zap .Error (err ))
174+ return "" , err
175+ }
176+ for _ , addr := range addrs {
177+ for _ , ipNet := range ipNets {
178+ switch v := addr .(type ) {
119179 case * net.IPAddr :
120- if options . ControllerNetwork .Contains (v .IP ) {
121- return "tcp/" + v .IP .String () + ":2019"
180+ if ipNet .Contains (v .IP ) {
181+ return "tcp/" + v .IP .String () + ":2019" , nil
122182 }
123- break
124183 case * net.IPNet :
125- if options . ControllerNetwork .Contains (v .IP ) {
126- return "tcp/" + v .IP .String () + ":2019"
184+ if ipNet .Contains (v .IP ) {
185+ return "tcp/" + v .IP .String () + ":2019" , nil
127186 }
128- break
129187 }
130188 }
131189 }
132190 }
133- return "tcp/localhost:2019"
191+
192+ return "tcp/0.0.0.0:2019" , nil
134193}
135194
136195func createOptions (flags caddycmd.Flags ) * config.Options {
@@ -140,7 +199,8 @@ func createOptions(flags caddycmd.Flags) *config.Options {
140199 processCaddyfileFlag := flags .Bool ("process-caddyfile" )
141200 pollingIntervalFlag := flags .Duration ("polling-interval" )
142201 modeFlag := flags .String ("mode" )
143- controllerSubnetFlag := flags .String ("controller-network" )
202+ controllerNetwork := flags .String ("controller-network" )
203+ controllerUrl := flags .String ("controller-url" )
144204 dockerSocketsFlag := flags .String ("docker-sockets" )
145205 dockerCertsPathFlag := flags .String ("docker-certs-path" )
146206 dockerAPIsVersionFlag := flags .String ("docker-apis-version" )
@@ -186,19 +246,23 @@ func createOptions(flags caddycmd.Flags) *config.Options {
186246 options .DockerAPIsVersion = strings .Split (dockerAPIsVersionFlag , "," )
187247 }
188248
189- if controllerIPRangeEnv := os .Getenv ("CADDY_CONTROLLER_NETWORK" ); controllerIPRangeEnv != "" {
190- _ , ipNet , err := net .ParseCIDR (controllerIPRangeEnv )
191- if err != nil {
192- log .Error ("Failed to parse CADDY_CONTROLLER_NETWORK" , zap .String ("CADDY_CONTROLLER_NETWORK" , controllerIPRangeEnv ), zap .Error (err ))
193- } else if ipNet != nil {
194- options .ControllerNetwork = ipNet
249+ if controllerNetworkEnv := os .Getenv ("CADDY_CONTROLLER_NETWORK" ); controllerNetworkEnv != "" {
250+ options .ControllerNetwork = controllerNetworkEnv
251+ } else {
252+ options .ControllerNetwork = controllerNetwork
253+ }
254+
255+ if controllerUrlEnv := os .Getenv ("CADDY_CONTROLLER_URL" ); controllerUrlEnv != "" {
256+ if url , err := url .Parse (controllerUrlEnv ); err != nil {
257+ log .Error ("Failed to parse CADDY_CONTROLLER_URL" , zap .String ("value" , controllerUrlEnv ), zap .Error (err ))
258+ } else {
259+ options .ControllerUrl = url
195260 }
196- } else if controllerSubnetFlag != "" {
197- _ , ipNet , err := net .ParseCIDR (controllerSubnetFlag )
198- if err != nil {
199- log .Error ("Failed to parse controller-network" , zap .String ("controller-network" , controllerSubnetFlag ), zap .Error (err ))
200- } else if ipNet != nil {
201- options .ControllerNetwork = ipNet
261+ } else if controllerUrl != "" {
262+ if url , err := url .Parse (controllerUrl ); err != nil {
263+ log .Error ("Failed to parse controller-url" , zap .String ("value" , controllerUrl ), zap .Error (err ))
264+ } else {
265+ options .ControllerUrl = url
202266 }
203267 }
204268
0 commit comments