mirror of https://github.com/docker/compose.git
sort containers to optimize scale down
Signed-off-by: Nicolas De Loof <nicolas.deloof@gmail.com>
This commit is contained in:
parent
c79aabde32
commit
de3da829ea
|
@ -127,6 +127,24 @@ func (c *convergence) ensureService(ctx context.Context, project *types.Project,
|
||||||
}
|
}
|
||||||
|
|
||||||
sort.Slice(containers, func(i, j int) bool {
|
sort.Slice(containers, func(i, j int) bool {
|
||||||
|
// select obsolete containers first, so they get removed as we scale down
|
||||||
|
if obsolete, _ := mustRecreate(service, containers[i], recreate); obsolete {
|
||||||
|
// i is obsolete, so must be first in the list
|
||||||
|
return true
|
||||||
|
}
|
||||||
|
if obsolete, _ := mustRecreate(service, containers[j], recreate); obsolete {
|
||||||
|
// j is obsolete, so must be first in the list
|
||||||
|
return false
|
||||||
|
}
|
||||||
|
|
||||||
|
// For up-to-date containers, sort by container number to preserve low-values in container numbers
|
||||||
|
ni, erri := strconv.Atoi(containers[i].Labels[api.ContainerNumberLabel])
|
||||||
|
nj, errj := strconv.Atoi(containers[j].Labels[api.ContainerNumberLabel])
|
||||||
|
if erri == nil && errj == nil {
|
||||||
|
return ni < nj
|
||||||
|
}
|
||||||
|
|
||||||
|
// If we don't get a container number (?) just sort by creation date
|
||||||
return containers[i].Created < containers[j].Created
|
return containers[i].Created < containers[j].Created
|
||||||
})
|
})
|
||||||
for i, container := range containers {
|
for i, container := range containers {
|
||||||
|
|
|
@ -5,6 +5,8 @@ services:
|
||||||
- db
|
- db
|
||||||
db:
|
db:
|
||||||
image: nginx:alpine
|
image: nginx:alpine
|
||||||
|
environment:
|
||||||
|
- MAYBE
|
||||||
front:
|
front:
|
||||||
image: nginx:alpine
|
image: nginx:alpine
|
||||||
deploy:
|
deploy:
|
||||||
|
|
|
@ -95,6 +95,78 @@ func TestScaleWithDepsCases(t *testing.T) {
|
||||||
checkServiceContainer(t, res.Combined(), "scale-deps-tests-db", NO_STATE_TO_CHECK, 1)
|
checkServiceContainer(t, res.Combined(), "scale-deps-tests-db", NO_STATE_TO_CHECK, 1)
|
||||||
}
|
}
|
||||||
|
|
||||||
|
func TestScaleUpAndDownPreserveContainerNumber(t *testing.T) {
|
||||||
|
const projectName = "scale-up-down-test"
|
||||||
|
|
||||||
|
c := NewCLI(t, WithEnv(
|
||||||
|
"COMPOSE_PROJECT_NAME="+projectName))
|
||||||
|
|
||||||
|
reset := func() {
|
||||||
|
c.RunDockerComposeCmd(t, "down", "--rmi", "all")
|
||||||
|
}
|
||||||
|
t.Cleanup(reset)
|
||||||
|
res := c.RunDockerComposeCmd(t, "--project-directory", "fixtures/scale", "up", "-d", "--scale", "db=2", "db")
|
||||||
|
res.Assert(t, icmd.Success)
|
||||||
|
|
||||||
|
res = c.RunDockerComposeCmd(t, "ps", "--format", "{{.Name}}", "db")
|
||||||
|
res.Assert(t, icmd.Success)
|
||||||
|
assert.Equal(t, strings.TrimSpace(res.Stdout()), projectName+"-db-1\n"+projectName+"-db-2")
|
||||||
|
|
||||||
|
t.Log("scale down removes replica #2")
|
||||||
|
res = c.RunDockerComposeCmd(t, "--project-directory", "fixtures/scale", "up", "-d", "--scale", "db=1", "db")
|
||||||
|
res.Assert(t, icmd.Success)
|
||||||
|
|
||||||
|
res = c.RunDockerComposeCmd(t, "ps", "--format", "{{.Name}}", "db")
|
||||||
|
res.Assert(t, icmd.Success)
|
||||||
|
assert.Equal(t, strings.TrimSpace(res.Stdout()), projectName+"-db-1")
|
||||||
|
|
||||||
|
t.Log("scale up restores replica #2")
|
||||||
|
res = c.RunDockerComposeCmd(t, "--project-directory", "fixtures/scale", "up", "-d", "--scale", "db=2", "db")
|
||||||
|
res.Assert(t, icmd.Success)
|
||||||
|
|
||||||
|
res = c.RunDockerComposeCmd(t, "ps", "--format", "{{.Name}}", "db")
|
||||||
|
res.Assert(t, icmd.Success)
|
||||||
|
assert.Equal(t, strings.TrimSpace(res.Stdout()), projectName+"-db-1\n"+projectName+"-db-2")
|
||||||
|
}
|
||||||
|
|
||||||
|
func TestScaleDownRemovesObsolete(t *testing.T) {
|
||||||
|
const projectName = "scale-down-obsolete-test"
|
||||||
|
c := NewCLI(t, WithEnv(
|
||||||
|
"COMPOSE_PROJECT_NAME="+projectName))
|
||||||
|
|
||||||
|
reset := func() {
|
||||||
|
c.RunDockerComposeCmd(t, "down", "--rmi", "all")
|
||||||
|
}
|
||||||
|
t.Cleanup(reset)
|
||||||
|
res := c.RunDockerComposeCmd(t, "--project-directory", "fixtures/scale", "up", "-d", "db")
|
||||||
|
res.Assert(t, icmd.Success)
|
||||||
|
|
||||||
|
res = c.RunDockerComposeCmd(t, "ps", "--format", "{{.Name}}", "db")
|
||||||
|
res.Assert(t, icmd.Success)
|
||||||
|
assert.Equal(t, strings.TrimSpace(res.Stdout()), projectName+"-db-1")
|
||||||
|
|
||||||
|
cmd := c.NewDockerComposeCmd(t, "--project-directory", "fixtures/scale", "up", "-d", "--scale", "db=2", "db")
|
||||||
|
res = icmd.RunCmd(cmd, func(cmd *icmd.Cmd) {
|
||||||
|
cmd.Env = append(cmd.Env, "MAYBE=value")
|
||||||
|
})
|
||||||
|
res.Assert(t, icmd.Success)
|
||||||
|
|
||||||
|
res = c.RunDockerComposeCmd(t, "ps", "--format", "{{.Name}}", "db")
|
||||||
|
res.Assert(t, icmd.Success)
|
||||||
|
assert.Equal(t, strings.TrimSpace(res.Stdout()), projectName+"-db-1\n"+projectName+"-db-2")
|
||||||
|
|
||||||
|
t.Log("scale down removes obsolete replica #1")
|
||||||
|
cmd = c.NewDockerComposeCmd(t, "--project-directory", "fixtures/scale", "up", "-d", "--scale", "db=1", "db")
|
||||||
|
res = icmd.RunCmd(cmd, func(cmd *icmd.Cmd) {
|
||||||
|
cmd.Env = append(cmd.Env, "MAYBE=value")
|
||||||
|
})
|
||||||
|
res.Assert(t, icmd.Success)
|
||||||
|
|
||||||
|
res = c.RunDockerComposeCmd(t, "ps", "--format", "{{.Name}}", "db")
|
||||||
|
res.Assert(t, icmd.Success)
|
||||||
|
assert.Equal(t, strings.TrimSpace(res.Stdout()), projectName+"-db-1")
|
||||||
|
}
|
||||||
|
|
||||||
func checkServiceContainer(t *testing.T, stdout, containerName, containerState string, count int) {
|
func checkServiceContainer(t *testing.T, stdout, containerName, containerState string, count int) {
|
||||||
found := 0
|
found := 0
|
||||||
lines := strings.Split(stdout, "\n")
|
lines := strings.Split(stdout, "\n")
|
||||||
|
|
Loading…
Reference in New Issue