Skip to content
This repository was archived by the owner on Feb 26, 2024. It is now read-only.

Commit 2175a37

Browse files
committed
feat(docker): fixed external ports
Determine free port and set it in Terraform file to be more consistent with ports and avoid downtimes when Terraform decides to change port numbers.
1 parent bb629c0 commit 2175a37

File tree

4 files changed

+54
-3
lines changed

4 files changed

+54
-3
lines changed

go.mod

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -17,6 +17,7 @@ require (
1717
github.com/google/go-cmp v0.5.8
1818
github.com/gookit/event v1.0.6
1919
github.com/hairyhenderson/gomplate/v3 v3.11.2
20+
github.com/phayes/freeport v0.0.0-20220201140144-74d24b5ae9f5
2021
github.com/saitho/golang-extended-fs/v2 v2.0.1
2122
github.com/shibukawa/configdir v0.0.0-20170330084843-e180dbdc8da0
2223
github.com/sirupsen/logrus v1.8.1

go.sum

Lines changed: 2 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -767,6 +767,8 @@ github.com/pascaldekloe/goe v0.1.0/go.mod h1:lzWF7FIEvWOWxwDKqyGYQf6ZUaNfKdP144T
767767
github.com/pelletier/go-toml v1.9.3 h1:zeC5b1GviRUyKYd6OJPvBU/mcVDVoL1OhT17FCt5dSQ=
768768
github.com/pelletier/go-toml v1.9.3/go.mod h1:u1nR/EPcESfeI/szUZKdtJ0xRNbUoANCkoOuaOx1Y+c=
769769
github.com/peterbourgon/diskv v2.0.1+incompatible/go.mod h1:uqqh8zWWbv1HBMNONnaR/tNboyR3/BZd58JJSHlUSCU=
770+
github.com/phayes/freeport v0.0.0-20220201140144-74d24b5ae9f5 h1:Ii+DKncOVM8Cu1Hc+ETb5K+23HdAMvESYE3ZJ5b5cMI=
771+
github.com/phayes/freeport v0.0.0-20220201140144-74d24b5ae9f5/go.mod h1:iIss55rKnNBTvrwdmkUpLnDpZoAHvWaiq5+iMmen4AE=
770772
github.com/pierrec/lz4 v2.5.2+incompatible/go.mod h1:pdkljMzZIN41W+lC3N2tnIh5sFi+IEE17M5jbnwPHcY=
771773
github.com/pierrec/lz4 v2.6.1+incompatible h1:9UY3+iC23yxF0UfGaYrGplQ+79Rg+h/q9FV9ix19jjM=
772774
github.com/pierrec/lz4 v2.6.1+incompatible/go.mod h1:pdkljMzZIN41W+lC3N2tnIh5sFi+IEE17M5jbnwPHcY=

modules/container/docker/deploy.go

Lines changed: 49 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -8,9 +8,11 @@ import (
88
"strconv"
99
"text/template"
1010

11+
"github.com/phayes/freeport"
1112
xfs "github.com/saitho/golang-extended-fs/v2"
1213

1314
container_docker_definitions "github.com/getstackhead/stackhead/modules/container/docker/definitions"
15+
"github.com/getstackhead/stackhead/project"
1416
"github.com/getstackhead/stackhead/system"
1517
)
1618

@@ -56,6 +58,43 @@ func resolveUserNameWithCache(userName string) (int, error) {
5658
return resolvedUserId, err
5759
}
5860

61+
func getPortMap(project *project.Project) (map[string]int, error) {
62+
dockerPortMap := map[string]int{}
63+
64+
// find ports for running containers
65+
for _, service := range project.Container.Services {
66+
res, _, err := system.RemoteRun("docker", "port", "stackhead-"+project.Name+"-"+service.Name)
67+
if err == nil { // ignore error (container not running)
68+
// e.g. 80/tcp -> 0.0.0.0:49155
69+
re := regexp.MustCompile(`(?P<Internal>\d+)\/tcp -> 0\.0\.0\.0:(?P<External>\d+)`)
70+
matches := re.FindAllStringSubmatch(res.String(), -1)
71+
for _, match := range matches {
72+
externalPort, _ := strconv.Atoi(match[re.SubexpIndex("External")])
73+
dockerPortMap[service.Name+"-"+match[re.SubexpIndex("Internal")]] = externalPort
74+
}
75+
}
76+
}
77+
78+
// determine ports for missing containers
79+
missingPortServices := []string{}
80+
for _, domain := range project.Domains {
81+
for _, expose := range domain.Expose {
82+
mapKey := expose.Service + "-" + strconv.Itoa(expose.InternalPort)
83+
if _, ok := dockerPortMap[mapKey]; !ok {
84+
missingPortServices = append(missingPortServices, mapKey)
85+
}
86+
}
87+
}
88+
ports, err := freeport.GetFreePorts(len(missingPortServices))
89+
if err != nil {
90+
return nil, fmt.Errorf("unable to determine free ports: " + err.Error())
91+
}
92+
for i := range missingPortServices {
93+
dockerPortMap[missingPortServices[i]] = ports[i]
94+
}
95+
return dockerPortMap, nil
96+
}
97+
5998
func (m Module) Deploy(modulesSettings interface{}) error {
6099
project := system.Context.Project
61100

@@ -146,9 +185,15 @@ func (m Module) Deploy(modulesSettings interface{}) error {
146185
},
147186
}
148187

188+
dockerPortMap, err := getPortMap(project)
189+
if err != nil {
190+
return fmt.Errorf("unable to determine free ports: " + err.Error())
191+
}
192+
149193
data := map[string]interface{}{
150-
"Context": system.Context,
151-
"DockerPaths": GetDockerPaths(),
194+
"Context": system.Context,
195+
"DockerPaths": GetDockerPaths(),
196+
"DockerPortMap": dockerPortMap,
152197
}
153198
dockerTf, err := system.RenderModuleTemplate(
154199
templates,
@@ -158,5 +203,7 @@ func (m Module) Deploy(modulesSettings interface{}) error {
158203
if err != nil {
159204
return err
160205
}
206+
207+
_ = xfs.WriteFile("ssh://"+project.GetTerraformDirectoryPath()+"/docker.tf", dockerTf)
161208
return xfs.WriteFile("ssh://"+project.GetTerraformDirectoryPath()+"/docker.tf", dockerTf)
162209
}

modules/container/docker/templates/project.tf.tmpl

Lines changed: 2 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -51,6 +51,7 @@ resource "docker_container" "stackhead-{{ $.Context.Project.Name }}-{{ $service.
5151
{{ if and $expose.InternalPort (eq $expose.Service $service.Name) }}
5252
ports {
5353
internal = {{ $expose.InternalPort }}
54+
external = {{ index $.DockerPortMap (printf "%s-%d" $expose.Service $expose.InternalPort) }}
5455
}
5556
{{ end }}
5657
{{- end }}
@@ -109,7 +110,7 @@ resource "docker_volume" "local-{{ $.Context.Project.Name }}-{{ $service.Name }}
109110
{{ end }}
110111

111112
{{ range $key := keys $globalVolumesDict }}
112-
{{ $value := get $globalVolumesDict $key }}
113+
{{ $value := get $globalVolumesDict $key }}
113114
resource "docker_volume" "global-{{ $.Context.Project.Name }}-{{ $key }}" {
114115
provider = docker.{{ $.Context.Project.Name }}
115116
name = "global-{{ $.Context.Project.Name }}-{{ $key }}"

0 commit comments

Comments
 (0)