1
1
package caddydockerproxy
2
2
3
3
import (
4
+ "encoding/json"
4
5
"flag"
6
+ "io/ioutil"
5
7
"net"
8
+ "net/http"
9
+ "net/url"
6
10
"os"
7
11
"regexp"
8
12
"strings"
@@ -31,35 +35,50 @@ func init() {
31
35
"Which mode this instance should run: standalone | controller | server" )
32
36
33
37
fs .String ("docker-sockets" , "" ,
34
- "Docker sockets comma separate" )
38
+ "Docker sockets comma separate.\n " +
39
+ "Applicable to modes: controller, standalone" )
35
40
36
41
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" )
38
44
39
45
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" )
41
48
42
49
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" )
44
57
45
58
fs .String ("ingress-networks" , "" ,
46
59
"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" )
48
62
49
63
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" )
51
66
52
67
fs .String ("label-prefix" , generator .DefaultLabelPrefix ,
53
- "Prefix for Docker labels" )
68
+ "Prefix for Docker labels.\n " +
69
+ "Applicable to modes: controller, standalone" )
54
70
55
71
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" )
57
74
58
75
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" )
60
78
61
79
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" )
63
82
64
83
return fs
65
84
}(),
@@ -75,9 +94,14 @@ func cmdFunc(flags caddycmd.Flags) (int, error) {
75
94
if options .Mode & config .Server == config .Server {
76
95
log .Info ("Running caddy proxy server" )
77
96
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 {
79
103
Admin : & caddy.AdminConfig {
80
- Listen : getAdminListen ( options ) ,
104
+ Listen : bindAddress ,
81
105
},
82
106
})
83
107
if err != nil {
@@ -87,8 +111,8 @@ func cmdFunc(flags caddycmd.Flags) (int, error) {
87
111
88
112
if options .Mode & config .Controller == config .Controller {
89
113
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 {
92
116
if err := caddy .Stop (); err != nil {
93
117
return 1 , err
94
118
}
@@ -100,37 +124,72 @@ func cmdFunc(flags caddycmd.Flags) (int, error) {
100
124
select {}
101
125
}
102
126
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
+ }
107
139
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 )
108
144
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
110
147
}
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 ) {
119
179
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
122
182
}
123
- break
124
183
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
127
186
}
128
- break
129
187
}
130
188
}
131
189
}
132
190
}
133
- return "tcp/localhost:2019"
191
+
192
+ return "tcp/0.0.0.0:2019" , nil
134
193
}
135
194
136
195
func createOptions (flags caddycmd.Flags ) * config.Options {
@@ -140,7 +199,8 @@ func createOptions(flags caddycmd.Flags) *config.Options {
140
199
processCaddyfileFlag := flags .Bool ("process-caddyfile" )
141
200
pollingIntervalFlag := flags .Duration ("polling-interval" )
142
201
modeFlag := flags .String ("mode" )
143
- controllerSubnetFlag := flags .String ("controller-network" )
202
+ controllerNetwork := flags .String ("controller-network" )
203
+ controllerUrl := flags .String ("controller-url" )
144
204
dockerSocketsFlag := flags .String ("docker-sockets" )
145
205
dockerCertsPathFlag := flags .String ("docker-certs-path" )
146
206
dockerAPIsVersionFlag := flags .String ("docker-apis-version" )
@@ -186,19 +246,23 @@ func createOptions(flags caddycmd.Flags) *config.Options {
186
246
options .DockerAPIsVersion = strings .Split (dockerAPIsVersionFlag , "," )
187
247
}
188
248
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
195
260
}
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
202
266
}
203
267
}
204
268
0 commit comments