mirror of https://github.com/docker/compose.git
Add service based network_mode
Signed-off-by: Ulysses Souza <ulyssessouza@gmail.com>
This commit is contained in:
parent
ea24e499e6
commit
83cc63c8ae
|
@ -69,7 +69,7 @@ func (o *projectOptions) toProject(services []string) (*types.Project, error) {
|
|||
}
|
||||
|
||||
if len(services) != 0 {
|
||||
s, err := project.GetServices(services)
|
||||
s, err := project.GetServices(services...)
|
||||
if err != nil {
|
||||
return nil, err
|
||||
}
|
||||
|
|
|
@ -32,7 +32,7 @@ func TestFilterServices(t *testing.T) {
|
|||
},
|
||||
{
|
||||
Name: "bar",
|
||||
NetworkMode: "service:zot",
|
||||
NetworkMode: types.NetworkModeServicePrefix + "zot",
|
||||
},
|
||||
{
|
||||
Name: "zot",
|
||||
|
|
2
go.mod
2
go.mod
|
@ -17,7 +17,7 @@ require (
|
|||
github.com/awslabs/goformation/v4 v4.15.6
|
||||
github.com/buger/goterm v0.0.0-20200322175922-2f3e71b85129
|
||||
github.com/cnabio/cnab-to-oci v0.3.1-beta1
|
||||
github.com/compose-spec/compose-go v0.0.0-20210217144939-9f2c61fe6b14
|
||||
github.com/compose-spec/compose-go v0.0.0-20210218184709-a75bbdcff7f3
|
||||
github.com/containerd/console v1.0.1
|
||||
github.com/containerd/containerd v1.4.3
|
||||
github.com/containerd/continuity v0.0.0-20200928162600-f2cc35102c2a // indirect
|
||||
|
|
4
go.sum
4
go.sum
|
@ -302,8 +302,8 @@ github.com/cncf/udpa/go v0.0.0-20191209042840-269d4d468f6f/go.mod h1:M8M6+tZqaGX
|
|||
github.com/cockroachdb/datadriven v0.0.0-20190809214429-80d97fb3cbaa/go.mod h1:zn76sxSg3SzpJ0PPJaLDCu+Bu0Lg3sKTORVIj19EIF8=
|
||||
github.com/codahale/hdrhistogram v0.0.0-20160425231609-f8ad88b59a58/go.mod h1:sE/e/2PUdi/liOCUjSTXgM1o87ZssimdTWN964YiIeI=
|
||||
github.com/codahale/hdrhistogram v0.0.0-20161010025455-3a0bb77429bd/go.mod h1:sE/e/2PUdi/liOCUjSTXgM1o87ZssimdTWN964YiIeI=
|
||||
github.com/compose-spec/compose-go v0.0.0-20210217144939-9f2c61fe6b14 h1:ezR3VeA9GLPRMXYC0JzuHOM6c9yHMbc6EHaZy6lEKRA=
|
||||
github.com/compose-spec/compose-go v0.0.0-20210217144939-9f2c61fe6b14/go.mod h1:flNthwF3kg+JioxATZWSsuuA2N3zGGwggDNNGoE9PHA=
|
||||
github.com/compose-spec/compose-go v0.0.0-20210218184709-a75bbdcff7f3 h1:cGJa3EMDcclDU21e/CVQJnDf3ZjnB6HN9TvxkFHpGq8=
|
||||
github.com/compose-spec/compose-go v0.0.0-20210218184709-a75bbdcff7f3/go.mod h1:flNthwF3kg+JioxATZWSsuuA2N3zGGwggDNNGoE9PHA=
|
||||
github.com/containerd/cgroups v0.0.0-20190919134610-bf292b21730f/go.mod h1:OApqhQ4XNSNC13gXIwDjhOQxjWa/NxkwZXJ1EvqT0ko=
|
||||
github.com/containerd/cgroups v0.0.0-20200531161412-0dbf7f05ba59/go.mod h1:pA0z1pT8KYB3TCXK/ocprsh7MAkoW8bZVzPdih9snmM=
|
||||
github.com/containerd/cgroups v0.0.0-20200710171044-318312a37340 h1:9atoWyI9RtXFwf7UDbme/6M8Ud0rFrx+Q3ZWgSnsxtw=
|
||||
|
|
|
@ -42,7 +42,17 @@ const (
|
|||
"Remove the custom name to scale the service.\n"
|
||||
)
|
||||
|
||||
func (s *composeService) ensureScale(ctx context.Context, actual []moby.Container, scale int, project *types.Project, service types.ServiceConfig) (*errgroup.Group, []moby.Container, error) {
|
||||
func (s *composeService) ensureScale(ctx context.Context, project *types.Project, service types.ServiceConfig) (*errgroup.Group, []moby.Container, error) {
|
||||
cState, err := GetContextContainerState(ctx)
|
||||
if err != nil {
|
||||
return nil, nil, err
|
||||
}
|
||||
observedState := cState.GetContainers()
|
||||
actual := observedState.filter(isService(service.Name))
|
||||
scale, err := getScale(service)
|
||||
if err != nil {
|
||||
return nil, nil, err
|
||||
}
|
||||
eg, _ := errgroup.WithContext(ctx)
|
||||
if len(actual) < scale {
|
||||
next, err := nextContainerNumber(actual)
|
||||
|
@ -75,15 +85,8 @@ func (s *composeService) ensureScale(ctx context.Context, actual []moby.Containe
|
|||
return eg, actual, nil
|
||||
}
|
||||
|
||||
func (s *composeService) ensureService(ctx context.Context, observedState Containers, project *types.Project, service types.ServiceConfig, recreate string) error {
|
||||
actual := observedState.filter(isService(service.Name))
|
||||
|
||||
scale, err := getScale(service)
|
||||
if err != nil {
|
||||
return err
|
||||
}
|
||||
|
||||
eg, actual, err := s.ensureScale(ctx, actual, scale, project, service)
|
||||
func (s *composeService) ensureService(ctx context.Context, project *types.Project, service types.ServiceConfig, recreate string) error {
|
||||
eg, actual, err := s.ensureScale(ctx, project, service)
|
||||
if err != nil {
|
||||
return err
|
||||
}
|
||||
|
@ -260,7 +263,12 @@ func (s *composeService) restartContainer(ctx context.Context, container moby.Co
|
|||
return nil
|
||||
}
|
||||
|
||||
func (s *composeService) createMobyContainer(ctx context.Context, project *types.Project, service types.ServiceConfig, name string, number int, container *moby.Container, autoRemove bool) error {
|
||||
func (s *composeService) createMobyContainer(ctx context.Context, project *types.Project, service types.ServiceConfig, name string, number int, container *moby.Container,
|
||||
autoRemove bool) error {
|
||||
cState, err := GetContextContainerState(ctx)
|
||||
if err != nil {
|
||||
return err
|
||||
}
|
||||
containerConfig, hostConfig, networkingConfig, err := s.getCreateOptions(ctx, project, service, number, container, autoRemove)
|
||||
if err != nil {
|
||||
return err
|
||||
|
@ -269,10 +277,14 @@ func (s *composeService) createMobyContainer(ctx context.Context, project *types
|
|||
if err != nil {
|
||||
return err
|
||||
}
|
||||
id := created.ID
|
||||
createdContainer := moby.Container{
|
||||
ID: created.ID,
|
||||
Labels: containerConfig.Labels,
|
||||
}
|
||||
cState.Add(createdContainer)
|
||||
for netName := range service.Networks {
|
||||
netwrk := project.Networks[netName]
|
||||
err = s.connectContainerToNetwork(ctx, id, netwrk.Name, service.Name, getContainerName(project.Name, service, number))
|
||||
err = s.connectContainerToNetwork(ctx, created.ID, netwrk.Name, service.Name, getContainerName(project.Name, service, number))
|
||||
if err != nil {
|
||||
return err
|
||||
}
|
||||
|
|
|
@ -70,6 +70,8 @@ func (s *composeService) Create(ctx context.Context, project *types.Project, opt
|
|||
if err != nil {
|
||||
return err
|
||||
}
|
||||
containerState := NewContainersState(observedState)
|
||||
ctx = context.WithValue(ctx, ContainersKey{}, containerState)
|
||||
|
||||
allServices := project.AllServices()
|
||||
allServiceNames := []string{}
|
||||
|
@ -92,8 +94,10 @@ func (s *composeService) Create(ctx context.Context, project *types.Project, opt
|
|||
}
|
||||
}
|
||||
|
||||
prepareNetworkMode(project)
|
||||
|
||||
return InDependencyOrder(ctx, project, func(c context.Context, service types.ServiceConfig) error {
|
||||
return s.ensureService(c, observedState, project, service, opts.Recreate)
|
||||
return s.ensureService(c, project, service, opts.Recreate)
|
||||
})
|
||||
}
|
||||
|
||||
|
@ -129,6 +133,27 @@ func prepareNetworks(project *types.Project) {
|
|||
}
|
||||
}
|
||||
|
||||
func prepareNetworkMode(p *types.Project) {
|
||||
outLoop:
|
||||
for i := range p.Services {
|
||||
dependency := getDependentServiceByNetwork(p.Services[i].NetworkMode)
|
||||
if dependency == "" {
|
||||
continue
|
||||
}
|
||||
if p.Services[i].DependsOn == nil {
|
||||
p.Services[i].DependsOn = make(types.DependsOnConfig)
|
||||
}
|
||||
for _, service := range p.Services {
|
||||
if service.Name == dependency {
|
||||
p.Services[i].DependsOn[service.Name] = types.ServiceDependency{
|
||||
Condition: types.ServiceConditionStarted,
|
||||
}
|
||||
continue outLoop
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
func (s *composeService) ensureNetworks(ctx context.Context, networks types.Networks) error {
|
||||
for _, network := range networks {
|
||||
err := s.ensureNetwork(ctx, network)
|
||||
|
@ -235,7 +260,11 @@ func (s *composeService) getCreateOptions(ctx context.Context, p *types.Project,
|
|||
portBindings := buildContainerPortBindingOptions(service)
|
||||
|
||||
resources := getDeployResources(service)
|
||||
networkMode := getNetworkMode(p, service)
|
||||
|
||||
networkMode, err := getNetworkMode(ctx, p, service)
|
||||
if err != nil {
|
||||
return nil, nil, nil, err
|
||||
}
|
||||
hostConfig := container.HostConfig{
|
||||
AutoRemove: autoRemove,
|
||||
Binds: binds,
|
||||
|
@ -335,6 +364,14 @@ func getVolumesFrom(project *types.Project, volumesFrom []string) ([]string, []s
|
|||
|
||||
}
|
||||
|
||||
func getDependentServiceByNetwork(networkMode string) string {
|
||||
baseService := ""
|
||||
if strings.HasPrefix(networkMode, types.NetworkModeServicePrefix) {
|
||||
return networkMode[len(types.NetworkModeServicePrefix):]
|
||||
}
|
||||
return baseService
|
||||
}
|
||||
|
||||
func (s *composeService) buildContainerVolumes(ctx context.Context, p types.Project, service types.ServiceConfig,
|
||||
inherit *moby.Container) (map[string]struct{}, []string, []mount.Mount, error) {
|
||||
var mounts = []mount.Mount{}
|
||||
|
@ -602,32 +639,42 @@ func getAliases(s types.ServiceConfig, c *types.ServiceNetworkConfig) []string {
|
|||
return aliases
|
||||
}
|
||||
|
||||
func getNetworkMode(p *types.Project, service types.ServiceConfig) container.NetworkMode {
|
||||
func getNetworkMode(ctx context.Context, p *types.Project, service types.ServiceConfig) (container.NetworkMode, error) {
|
||||
cState, err := GetContextContainerState(ctx)
|
||||
if err != nil {
|
||||
return container.NetworkMode("none"), nil
|
||||
}
|
||||
observedState := cState.GetContainers()
|
||||
|
||||
mode := service.NetworkMode
|
||||
if mode == "" {
|
||||
if len(p.Networks) > 0 {
|
||||
for name := range getNetworksForService(service) {
|
||||
return container.NetworkMode(p.Networks[name].Name)
|
||||
return container.NetworkMode(p.Networks[name].Name), nil
|
||||
}
|
||||
}
|
||||
return container.NetworkMode("none")
|
||||
return container.NetworkMode("none"), nil
|
||||
}
|
||||
|
||||
// FIXME incomplete implementation
|
||||
if strings.HasPrefix(mode, "service:") {
|
||||
panic("Not yet implemented")
|
||||
depServiceNetworkMode := getDependentServiceByNetwork(service.NetworkMode)
|
||||
if depServiceNetworkMode != "" {
|
||||
depServiceContainers := observedState.filter(isService(depServiceNetworkMode))
|
||||
if len(depServiceContainers) > 0 {
|
||||
return container.NetworkMode(types.NetworkModeContainerPrefix + depServiceContainers[0].ID), nil
|
||||
}
|
||||
return container.NetworkMode("none"),
|
||||
fmt.Errorf(`no containers started for network_mode %q in service %q -> %v`,
|
||||
mode, service.Name, observedState)
|
||||
}
|
||||
if strings.HasPrefix(mode, "container:") {
|
||||
panic("Not yet implemented")
|
||||
}
|
||||
|
||||
return container.NetworkMode(mode)
|
||||
return container.NetworkMode(mode), nil
|
||||
}
|
||||
|
||||
func getNetworksForService(s types.ServiceConfig) map[string]*types.ServiceNetworkConfig {
|
||||
if len(s.Networks) > 0 {
|
||||
return s.Networks
|
||||
}
|
||||
if s.NetworkMode != "" {
|
||||
return nil
|
||||
}
|
||||
return map[string]*types.ServiceNetworkConfig{"default": nil}
|
||||
}
|
||||
|
||||
|
|
|
@ -30,6 +30,16 @@ import (
|
|||
)
|
||||
|
||||
func (s *composeService) RunOneOffContainer(ctx context.Context, project *types.Project, opts compose.RunOptions) (int, error) {
|
||||
observedState, err := s.apiClient.ContainerList(ctx, apitypes.ContainerListOptions{
|
||||
Filters: filters.NewArgs(projectFilter(project.Name)),
|
||||
All: true,
|
||||
})
|
||||
if err != nil {
|
||||
return 0, err
|
||||
}
|
||||
containerState := NewContainersState(observedState)
|
||||
ctx = context.WithValue(ctx, ContainersKey{}, containerState)
|
||||
|
||||
service, err := project.GetService(opts.Service)
|
||||
if err != nil {
|
||||
return 0, err
|
||||
|
|
|
@ -0,0 +1,102 @@
|
|||
/*
|
||||
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 compose
|
||||
|
||||
import (
|
||||
"context"
|
||||
|
||||
"github.com/docker/docker/api/types"
|
||||
"github.com/pkg/errors"
|
||||
)
|
||||
|
||||
// ContainersKey is the context key to access context value os a ContainersStatus
|
||||
type ContainersKey struct{}
|
||||
|
||||
// ContainersState state management interface
|
||||
type ContainersState interface {
|
||||
Get(string) *types.Container
|
||||
GetContainers() Containers
|
||||
Add(c types.Container)
|
||||
AddAll(cs Containers)
|
||||
Remove(string) types.Container
|
||||
}
|
||||
|
||||
// NewContainersState creates a new container state manager
|
||||
func NewContainersState(cs Containers) ContainersState {
|
||||
s := containersState{
|
||||
observedContainers: &cs,
|
||||
}
|
||||
return &s
|
||||
}
|
||||
|
||||
// ContainersStatus works as a collection container for the observed containers
|
||||
type containersState struct {
|
||||
observedContainers *Containers
|
||||
}
|
||||
|
||||
func (s *containersState) AddAll(cs Containers) {
|
||||
for _, c := range cs {
|
||||
lValue := append(*s.observedContainers, c)
|
||||
s.observedContainers = &lValue
|
||||
}
|
||||
}
|
||||
|
||||
func (s *containersState) Add(c types.Container) {
|
||||
if s.Get(c.ID) == nil {
|
||||
lValue := append(*s.observedContainers, c)
|
||||
s.observedContainers = &lValue
|
||||
}
|
||||
}
|
||||
|
||||
func (s *containersState) Remove(id string) types.Container {
|
||||
var c types.Container
|
||||
var newObserved Containers
|
||||
for _, o := range *s.observedContainers {
|
||||
if o.ID != id {
|
||||
c = o
|
||||
continue
|
||||
}
|
||||
newObserved = append(newObserved, o)
|
||||
}
|
||||
s.observedContainers = &newObserved
|
||||
return c
|
||||
}
|
||||
|
||||
func (s *containersState) Get(id string) *types.Container {
|
||||
for _, o := range *s.observedContainers {
|
||||
if id == o.ID {
|
||||
return &o
|
||||
}
|
||||
}
|
||||
return nil
|
||||
}
|
||||
|
||||
func (s *containersState) GetContainers() Containers {
|
||||
if s.observedContainers != nil && *s.observedContainers != nil {
|
||||
return *s.observedContainers
|
||||
}
|
||||
return make(Containers, 0)
|
||||
}
|
||||
|
||||
// GetContextContainerState gets the container state manager
|
||||
func GetContextContainerState(ctx context.Context) (ContainersState, error) {
|
||||
cState, ok := ctx.Value(ContainersKey{}).(*containersState)
|
||||
if !ok {
|
||||
return nil, errors.New("containers' containersState not available in context")
|
||||
}
|
||||
return cState, nil
|
||||
}
|
|
@ -1,4 +1,9 @@
|
|||
services:
|
||||
mydb:
|
||||
image: mysql
|
||||
network_mode: "service:db"
|
||||
environment:
|
||||
- MYSQL_ALLOW_EMPTY_PASSWORD=yes
|
||||
db:
|
||||
image: gtardif/sentences-db
|
||||
networks:
|
||||
|
|
Loading…
Reference in New Issue