From 30f8878fbcc8eb06e4f483e8f8d3adad13c46fb9 Mon Sep 17 00:00:00 2001 From: Nicolas De Loof Date: Sun, 16 Nov 2025 18:49:48 +0100 Subject: [PATCH] Fix support for port range Signed-off-by: Nicolas De Loof --- pkg/compose/create.go | 23 +++++++++++++++----- pkg/e2e/expose_test.go | 48 ++++++++++++++++++++++++++++++++++++++++++ 2 files changed, 66 insertions(+), 5 deletions(-) create mode 100644 pkg/e2e/expose_test.go diff --git a/pkg/compose/create.go b/pkg/compose/create.go index 59dc568714..dc573fb5d2 100644 --- a/pkg/compose/create.go +++ b/pkg/compose/create.go @@ -210,11 +210,17 @@ func (s *composeService) getCreateConfigs(ctx context.Context, if err != nil { return createConfigs{}, err } + + exposed, err := buildContainerPorts(service) + if err != nil { + return createConfigs{}, err + } + containerConfig := container.Config{ Hostname: service.Hostname, Domainname: service.DomainName, User: service.User, - ExposedPorts: buildContainerPorts(service), + ExposedPorts: exposed, Tty: tty, OpenStdin: stdinOpen, StdinOnce: opts.AttachStdin && stdinOpen, @@ -763,17 +769,24 @@ func setBlkio(blkio *types.BlkioConfig, resources *container.Resources) { } } -func buildContainerPorts(s types.ServiceConfig) nat.PortSet { +func buildContainerPorts(s types.ServiceConfig) (nat.PortSet, error) { ports := nat.PortSet{} for _, s := range s.Expose { - p := nat.Port(s) - ports[p] = struct{}{} + proto, port := nat.SplitProtoPort(s) + start, end, err := nat.ParsePortRange(port) + if err != nil { + return nil, err + } + for i := start; i <= end; i++ { + p := nat.Port(fmt.Sprintf("%d/%s", i, proto)) + ports[p] = struct{}{} + } } for _, p := range s.Ports { p := nat.Port(fmt.Sprintf("%d/%s", p.Target, p.Protocol)) ports[p] = struct{}{} } - return ports + return ports, nil } func buildContainerPortBindingOptions(s types.ServiceConfig) nat.PortMap { diff --git a/pkg/e2e/expose_test.go b/pkg/e2e/expose_test.go new file mode 100644 index 0000000000..438f7b5490 --- /dev/null +++ b/pkg/e2e/expose_test.go @@ -0,0 +1,48 @@ +//go:build !windows + +/* + Copyright 2020 Docker Compose CLI authors + + Licensed under the Apache License, Version 2.0 (the "License"); + you may not use this file except in compliance with the License. + You may obtain a copy of the License at + + http://www.apache.org/licenses/LICENSE-2.0 + + Unless required by applicable law or agreed to in writing, software + distributed under the License is distributed on an "AS IS" BASIS, + WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + See the License for the specific language governing permissions and + limitations under the License. +*/ + +package e2e + +import ( + "os" + "path/filepath" + "testing" + + "gotest.tools/v3/assert" +) + +// see https://github.com/docker/compose/issues/13378 +func TestExposeRange(t *testing.T) { + c := NewParallelCLI(t) + + f := filepath.Join(t.TempDir(), "compose.yaml") + err := os.WriteFile(f, []byte(` +name: test-expose-range +services: + test: + image: alpine + expose: + - "9091-9092" +`), 0o644) + assert.NilError(t, err) + + t.Cleanup(func() { + c.cleanupWithDown(t, "test-expose-range") + }) + c.RunDockerComposeCmd(t, "-f", f, "up") +}