Skip to content

Commit 1a98a70

Browse files
gloursndeloof
authored andcommitted
add scale command
Signed-off-by: Guillaume Lours <[email protected]>
1 parent 19bbb12 commit 1a98a70

File tree

15 files changed

+404
-1
lines changed

15 files changed

+404
-1
lines changed

cmd/compose/compose.go

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -476,6 +476,7 @@ func RootCommand(dockerCli command.Cli, backend api.Service) *cobra.Command { //
476476
createCommand(&opts, dockerCli, backend),
477477
copyCommand(&opts, dockerCli, backend),
478478
waitCommand(&opts, dockerCli, backend),
479+
scaleCommand(&opts, dockerCli, backend),
479480
alphaCommand(&opts, dockerCli, backend),
480481
)
481482

cmd/compose/scale.go

Lines changed: 108 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,108 @@
1+
/*
2+
Copyright 2020 Docker Compose CLI authors
3+
4+
Licensed under the Apache License, Version 2.0 (the "License");
5+
you may not use this file except in compliance with the License.
6+
You may obtain a copy of the License at
7+
8+
http://www.apache.org/licenses/LICENSE-2.0
9+
10+
Unless required by applicable law or agreed to in writing, software
11+
distributed under the License is distributed on an "AS IS" BASIS,
12+
WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
13+
See the License for the specific language governing permissions and
14+
limitations under the License.
15+
*/
16+
17+
package compose
18+
19+
import (
20+
"context"
21+
"strconv"
22+
"strings"
23+
24+
"github.com/docker/cli/cli/command"
25+
26+
"github.com/compose-spec/compose-go/types"
27+
"github.com/pkg/errors"
28+
"golang.org/x/exp/maps"
29+
30+
"github.com/docker/compose/v2/pkg/api"
31+
"github.com/spf13/cobra"
32+
)
33+
34+
type scaleOptions struct {
35+
*ProjectOptions
36+
noDeps bool
37+
}
38+
39+
func scaleCommand(p *ProjectOptions, dockerCli command.Cli, backend api.Service) *cobra.Command {
40+
opts := scaleOptions{
41+
ProjectOptions: p,
42+
}
43+
scaleCmd := &cobra.Command{
44+
Use: "scale [SERVICE=REPLICAS...]",
45+
Short: "Scale services ",
46+
Args: cobra.MinimumNArgs(1),
47+
RunE: Adapt(func(ctx context.Context, args []string) error {
48+
serviceTuples, err := parseServicesReplicasArgs(args)
49+
if err != nil {
50+
return err
51+
}
52+
return runScale(ctx, dockerCli, backend, opts, serviceTuples)
53+
}),
54+
ValidArgsFunction: completeServiceNames(dockerCli, p),
55+
}
56+
flags := scaleCmd.Flags()
57+
flags.BoolVar(&opts.noDeps, "no-deps", false, "Don't start linked services.")
58+
59+
return scaleCmd
60+
}
61+
62+
func runScale(ctx context.Context, dockerCli command.Cli, backend api.Service, opts scaleOptions, serviceReplicaTuples map[string]int) error {
63+
services := maps.Keys(serviceReplicaTuples)
64+
project, err := opts.ToProject(dockerCli, services)
65+
if err != nil {
66+
return err
67+
}
68+
69+
if opts.noDeps {
70+
if err := project.ForServices(services, types.IgnoreDependencies); err != nil {
71+
return err
72+
}
73+
}
74+
75+
for key, value := range serviceReplicaTuples {
76+
for i, service := range project.Services {
77+
if service.Name != key {
78+
continue
79+
}
80+
if service.Deploy == nil {
81+
service.Deploy = &types.DeployConfig{}
82+
}
83+
scale := uint64(value)
84+
service.Deploy.Replicas = &scale
85+
project.Services[i] = service
86+
break
87+
}
88+
}
89+
90+
return backend.Scale(ctx, project, api.ScaleOptions{Services: services})
91+
}
92+
93+
func parseServicesReplicasArgs(args []string) (map[string]int, error) {
94+
serviceReplicaTuples := map[string]int{}
95+
for _, arg := range args {
96+
key, val, ok := strings.Cut(arg, "=")
97+
if !ok || key == "" || val == "" {
98+
return nil, errors.Errorf("Invalide scale specifier %q.", arg)
99+
}
100+
intValue, err := strconv.Atoi(val)
101+
102+
if err != nil {
103+
return nil, errors.Errorf("Invalide scale specifier, can't parse replicate value to int %q.", arg)
104+
}
105+
serviceReplicaTuples[key] = intValue
106+
}
107+
return serviceReplicaTuples, nil
108+
}

docs/reference/compose.md

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -26,6 +26,7 @@ Define and run multi-container applications with Docker.
2626
| [`restart`](compose_restart.md) | Restart service containers |
2727
| [`rm`](compose_rm.md) | Removes stopped service containers |
2828
| [`run`](compose_run.md) | Run a one-off command on a service. |
29+
| [`scale`](compose_scale.md) | Scale services |
2930
| [`start`](compose_start.md) | Start services |
3031
| [`stop`](compose_stop.md) | Stop services |
3132
| [`top`](compose_top.md) | Display the running processes |

docs/reference/compose_alpha_scale.md

Lines changed: 15 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,15 @@
1+
# docker compose alpha scale
2+
3+
<!---MARKER_GEN_START-->
4+
Scale services
5+
6+
### Options
7+
8+
| Name | Type | Default | Description |
9+
|:------------|:-----|:--------|:--------------------------------|
10+
| `--dry-run` | | | Execute command in dry run mode |
11+
| `--no-deps` | | | Don't start linked services. |
12+
13+
14+
<!---MARKER_GEN_END-->
15+

docs/reference/compose_scale.md

Lines changed: 15 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,15 @@
1+
# docker compose scale
2+
3+
<!---MARKER_GEN_START-->
4+
Scale services
5+
6+
### Options
7+
8+
| Name | Type | Default | Description |
9+
|:------------|:-----|:--------|:--------------------------------|
10+
| `--dry-run` | | | Execute command in dry run mode |
11+
| `--no-deps` | | | Don't start linked services. |
12+
13+
14+
<!---MARKER_GEN_END-->
15+

docs/reference/docker_compose.yaml

Lines changed: 2 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -165,6 +165,7 @@ cname:
165165
- docker compose restart
166166
- docker compose rm
167167
- docker compose run
168+
- docker compose scale
168169
- docker compose start
169170
- docker compose stop
170171
- docker compose top
@@ -192,6 +193,7 @@ clink:
192193
- docker_compose_restart.yaml
193194
- docker_compose_rm.yaml
194195
- docker_compose_run.yaml
196+
- docker_compose_scale.yaml
195197
- docker_compose_start.yaml
196198
- docker_compose_stop.yaml
197199
- docker_compose_top.yaml
Lines changed: 35 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,35 @@
1+
command: docker compose alpha scale
2+
short: Scale services
3+
long: Scale services
4+
usage: docker compose alpha scale [SERVICE=REPLICAS...]
5+
pname: docker compose alpha
6+
plink: docker_compose_alpha.yaml
7+
options:
8+
- option: no-deps
9+
value_type: bool
10+
default_value: "false"
11+
description: Don't start linked services.
12+
deprecated: false
13+
hidden: false
14+
experimental: false
15+
experimentalcli: false
16+
kubernetes: false
17+
swarm: false
18+
inherited_options:
19+
- option: dry-run
20+
value_type: bool
21+
default_value: "false"
22+
description: Execute command in dry run mode
23+
deprecated: false
24+
hidden: false
25+
experimental: false
26+
experimentalcli: false
27+
kubernetes: false
28+
swarm: false
29+
deprecated: false
30+
hidden: false
31+
experimental: false
32+
experimentalcli: true
33+
kubernetes: false
34+
swarm: false
35+
Lines changed: 35 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,35 @@
1+
command: docker compose scale
2+
short: Scale services
3+
long: Scale services
4+
usage: docker compose scale [SERVICE=REPLICAS...]
5+
pname: docker compose
6+
plink: docker_compose.yaml
7+
options:
8+
- option: no-deps
9+
value_type: bool
10+
default_value: "false"
11+
description: Don't start linked services.
12+
deprecated: false
13+
hidden: false
14+
experimental: false
15+
experimentalcli: false
16+
kubernetes: false
17+
swarm: false
18+
inherited_options:
19+
- option: dry-run
20+
value_type: bool
21+
default_value: "false"
22+
description: Execute command in dry run mode
23+
deprecated: false
24+
hidden: false
25+
experimental: false
26+
experimentalcli: false
27+
kubernetes: false
28+
swarm: false
29+
deprecated: false
30+
hidden: false
31+
experimental: false
32+
experimentalcli: false
33+
kubernetes: false
34+
swarm: false
35+

go.mod

Lines changed: 2 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -51,6 +51,8 @@ require (
5151
gotest.tools/v3 v3.5.0
5252
)
5353

54+
require golang.org/x/exp v0.0.0-20230713183714-613f0c0eb8a1
55+
5456
require (
5557
github.com/AdaLogics/go-fuzz-headers v0.0.0-20230106234847-43070de90fa1 // indirect
5658
github.com/Azure/go-ansiterm v0.0.0-20210617225240-d185dfc1b5a1 // indirect
@@ -155,7 +157,6 @@ require (
155157
go.opentelemetry.io/otel/metric v0.37.0 // indirect
156158
go.opentelemetry.io/proto/otlp v0.19.0 // indirect
157159
golang.org/x/crypto v0.11.0 // indirect
158-
golang.org/x/exp v0.0.0-20230713183714-613f0c0eb8a1 // indirect
159160
golang.org/x/mod v0.11.0 // indirect
160161
golang.org/x/net v0.12.0 // indirect
161162
golang.org/x/oauth2 v0.10.0 // indirect

pkg/api/api.go

Lines changed: 6 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -88,6 +88,12 @@ type Service interface {
8888
Viz(ctx context.Context, project *types.Project, options VizOptions) (string, error)
8989
// Wait blocks until at least one of the services' container exits
9090
Wait(ctx context.Context, projectName string, options WaitOptions) (int64, error)
91+
// Scale manages numbers of container instances running per service
92+
Scale(ctx context.Context, project *types.Project, options ScaleOptions) error
93+
}
94+
95+
type ScaleOptions struct {
96+
Services []string
9197
}
9298

9399
type WaitOptions struct {

0 commit comments

Comments
 (0)