Skip to content

Commit b53efb3

Browse files
committed
Added support for deploying load balanced clusters.
1 parent de14659 commit b53efb3

5 files changed

Lines changed: 277 additions & 38 deletions

File tree

clusterdef/cluster.go

Lines changed: 3 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -26,8 +26,9 @@ type DockerCluster struct {
2626
CbasMemoryMB int `yaml:"cbas-memory,omitempty"`
2727
EventingMemoryMB int `yaml:"eventing-memory,omitempty"`
2828

29-
Analytics AnalyticsSettings `yaml:"analytics,omitempty"`
30-
EnableDNS bool `yaml:"dns,omitempty"`
29+
Analytics AnalyticsSettings `yaml:"analytics,omitempty"`
30+
EnableDNS bool `yaml:"dns,omitempty"`
31+
EnableLoadBalancer bool `yaml:"load-balancer,omitempty"`
3132
}
3233

3334
type AnalyticsSettings struct {

deployment/dockerdeploy/clusterinfo.go

Lines changed: 3 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -32,6 +32,9 @@ type ClusterInfo struct {
3232
Expiry time.Time
3333
Nodes []*ClusterNodeInfo
3434
DnsName string
35+
36+
// TODO(brett19): this should not be here
37+
LoadBalancerIPAddress string
3538
}
3639

3740
var _ (deployment.ClusterInfo) = (*ClusterInfo)(nil)

deployment/dockerdeploy/controller.go

Lines changed: 140 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -291,6 +291,146 @@ func (c *Controller) DeployS3MockNode(ctx context.Context, clusterID string, exp
291291
return node, nil
292292
}
293293

294+
func (c *Controller) DeployNginxNode(ctx context.Context, clusterID string, expiry time.Duration) (*NodeInfo, error) {
295+
nodeID := "nginx"
296+
logger := c.Logger.With(zap.String("nodeId", nodeID))
297+
298+
logger.Debug("deploying nginx node")
299+
300+
containerName := "cbdynnode-nginx-" + clusterID
301+
302+
createResult, err := c.DockerCli.ContainerCreate(context.Background(), &container.Config{
303+
Image: "nginx",
304+
Labels: map[string]string{
305+
"com.couchbase.dyncluster.cluster_id": clusterID,
306+
"com.couchbase.dyncluster.type": "nginx",
307+
"com.couchbase.dyncluster.purpose": "nginx backing for cluster",
308+
"com.couchbase.dyncluster.node_id": nodeID,
309+
},
310+
// same effect as ntp
311+
Volumes: map[string]struct{}{"/etc/localtime:/etc/localtime": {}},
312+
}, &container.HostConfig{
313+
AutoRemove: true,
314+
NetworkMode: container.NetworkMode(c.NetworkName),
315+
CapAdd: []string{"NET_ADMIN"},
316+
Resources: container.Resources{
317+
Ulimits: []*units.Ulimit{
318+
{Name: "nofile", Soft: 200000, Hard: 200000},
319+
},
320+
},
321+
}, nil, nil, containerName)
322+
if err != nil {
323+
return nil, errors.Wrap(err, "failed to create container")
324+
}
325+
326+
containerID := createResult.ID
327+
328+
logger.Debug("container created, starting", zap.String("container", containerID))
329+
330+
err = c.DockerCli.ContainerStart(context.Background(), containerID, container.StartOptions{})
331+
if err != nil {
332+
return nil, errors.Wrap(err, "failed to start container")
333+
}
334+
335+
expiryTime := time.Time{}
336+
if expiry > 0 {
337+
expiryTime = time.Now().Add(expiry)
338+
}
339+
340+
err = c.WriteNodeState(ctx, containerID, &DockerNodeState{
341+
Expiry: expiryTime,
342+
})
343+
if err != nil {
344+
return nil, errors.Wrap(err, "failed write node state")
345+
}
346+
347+
// Cheap hack for simpler parsing...
348+
allNodes, err := c.ListNodes(ctx)
349+
if err != nil {
350+
return nil, errors.Wrap(err, "failed to list nodes")
351+
}
352+
353+
var node *NodeInfo
354+
for _, allNode := range allNodes {
355+
if allNode.ContainerID == containerID {
356+
node = allNode
357+
}
358+
}
359+
if node == nil {
360+
return nil, errors.New("failed to find newly created container")
361+
}
362+
363+
logger.Debug("container has started, waiting for it to get ready", zap.String("address", node.IPAddress))
364+
365+
for {
366+
resp, err := http.Get(fmt.Sprintf("http://%s:%d", node.IPAddress, 80))
367+
if err != nil || resp.StatusCode != 200 {
368+
logger.Debug("nginx not ready yet", zap.Error(err))
369+
time.Sleep(100 * time.Millisecond)
370+
continue
371+
}
372+
373+
break
374+
}
375+
376+
logger.Debug("container is ready!")
377+
378+
return node, nil
379+
}
380+
381+
func (c *Controller) UpdateNginxConfig(ctx context.Context, containerID string, addrs []string) error {
382+
c.Logger.Debug("writing nginx config", zap.String("container", containerID), zap.Any("addrs", addrs))
383+
384+
var nginxConf string
385+
writeForwardedPort := func(port string) {
386+
if len(addrs) > 0 {
387+
nginxConf += "upstream backend" + port + " {\n"
388+
for _, addr := range addrs {
389+
nginxConf += " server " + addr + ":" + port + ";\n"
390+
}
391+
nginxConf += "}\n"
392+
nginxConf += "server {\n"
393+
nginxConf += " listen " + port + ";\n"
394+
nginxConf += " location / {\n"
395+
nginxConf += " proxy_pass http://backend" + port + ";\n"
396+
nginxConf += " proxy_set_header Host $http_host;\n"
397+
nginxConf += " proxy_set_header X-Real-IP $remote_addr;\n"
398+
nginxConf += " proxy_set_header X-Forwarded-For $proxy_add_x_forwarded_for;\n"
399+
nginxConf += " }\n"
400+
nginxConf += "}\n"
401+
}
402+
}
403+
writeForwardedPort("8091")
404+
writeForwardedPort("8092")
405+
writeForwardedPort("8093")
406+
writeForwardedPort("8094")
407+
writeForwardedPort("8095")
408+
writeForwardedPort("8096")
409+
410+
confBytes := []byte(nginxConf)
411+
412+
tarBuf := bytes.NewBuffer(nil)
413+
tarFile := tar.NewWriter(tarBuf)
414+
tarFile.WriteHeader(&tar.Header{
415+
Name: "cb.conf",
416+
Size: int64(len(confBytes)),
417+
})
418+
tarFile.Write(confBytes)
419+
tarFile.Flush()
420+
421+
err := c.DockerCli.CopyToContainer(ctx, containerID, "/etc/nginx/conf.d/", tarBuf, container.CopyToContainerOptions{})
422+
if err != nil {
423+
return errors.Wrap(err, "failed to write nginx config")
424+
}
425+
426+
err = c.execCmd(ctx, containerID, []string{"nginx", "-s", "reload"})
427+
if err != nil {
428+
return errors.Wrap(err, "failed to reload nginx config")
429+
}
430+
431+
return nil
432+
}
433+
294434
type DeployNodeOptions struct {
295435
Purpose string
296436
Expiry time.Duration

0 commit comments

Comments
 (0)