|
|
@@ -48,6 +48,20 @@ import (
|
|
|
"github.com/docker/compose/v2/pkg/utils"
|
|
|
)
|
|
|
|
|
|
+type createOptions struct {
|
|
|
+ AutoRemove bool
|
|
|
+ AttachStdin bool
|
|
|
+ UseNetworkAliases bool
|
|
|
+ Labels types.Labels
|
|
|
+}
|
|
|
+
|
|
|
+type createConfigs struct {
|
|
|
+ Container *container.Config
|
|
|
+ Host *container.HostConfig
|
|
|
+ Network *network.NetworkingConfig
|
|
|
+ Links []string
|
|
|
+}
|
|
|
+
|
|
|
func (s *composeService) Create(ctx context.Context, project *types.Project, options api.CreateOptions) error {
|
|
|
return progress.RunWithTitle(ctx, func(ctx context.Context) error {
|
|
|
return s.create(ctx, project, options)
|
|
|
@@ -166,18 +180,16 @@ func (s *composeService) ensureProjectVolumes(ctx context.Context, project *type
|
|
|
return nil
|
|
|
}
|
|
|
|
|
|
-func (s *composeService) getCreateOptions(ctx context.Context,
|
|
|
+func (s *composeService) getCreateConfigs(ctx context.Context,
|
|
|
p *types.Project,
|
|
|
service types.ServiceConfig,
|
|
|
number int,
|
|
|
inherit *moby.Container,
|
|
|
- autoRemove, attachStdin bool,
|
|
|
- labels types.Labels,
|
|
|
-) (*container.Config, *container.HostConfig, *network.NetworkingConfig, error) {
|
|
|
-
|
|
|
- labels, err := s.prepareLabels(labels, service, number)
|
|
|
+ opts createOptions,
|
|
|
+) (createConfigs, error) {
|
|
|
+ labels, err := s.prepareLabels(opts.Labels, service, number)
|
|
|
if err != nil {
|
|
|
- return nil, nil, nil, err
|
|
|
+ return createConfigs{}, err
|
|
|
}
|
|
|
|
|
|
var (
|
|
|
@@ -196,11 +208,6 @@ func (s *composeService) getCreateOptions(ctx context.Context,
|
|
|
stdinOpen = service.StdinOpen
|
|
|
)
|
|
|
|
|
|
- binds, mounts, err := s.buildContainerVolumes(ctx, *p, service, inherit)
|
|
|
- if err != nil {
|
|
|
- return nil, nil, nil, err
|
|
|
- }
|
|
|
-
|
|
|
proxyConfig := types.MappingWithEquals(s.configFile().ParseProxyConfig(s.apiClient().DaemonHost(), nil))
|
|
|
env := proxyConfig.OverrideBy(service.Environment)
|
|
|
|
|
|
@@ -211,8 +218,8 @@ func (s *composeService) getCreateOptions(ctx context.Context,
|
|
|
ExposedPorts: buildContainerPorts(service),
|
|
|
Tty: tty,
|
|
|
OpenStdin: stdinOpen,
|
|
|
- StdinOnce: attachStdin && stdinOpen,
|
|
|
- AttachStdin: attachStdin,
|
|
|
+ StdinOnce: opts.AttachStdin && stdinOpen,
|
|
|
+ AttachStdin: opts.AttachStdin,
|
|
|
AttachStderr: true,
|
|
|
AttachStdout: true,
|
|
|
Cmd: runCmd,
|
|
|
@@ -228,20 +235,7 @@ func (s *composeService) getCreateOptions(ctx context.Context,
|
|
|
StopTimeout: ToSeconds(service.StopGracePeriod),
|
|
|
}
|
|
|
|
|
|
- portBindings := buildContainerPortBindingOptions(service)
|
|
|
-
|
|
|
- resources := getDeployResources(service)
|
|
|
-
|
|
|
- if service.NetworkMode == "" {
|
|
|
- service.NetworkMode = getDefaultNetworkMode(p, service)
|
|
|
- }
|
|
|
-
|
|
|
- var networkConfig *network.NetworkingConfig
|
|
|
- for _, id := range service.NetworksByPriority() {
|
|
|
- networkConfig = s.createNetworkConfig(p, service, id)
|
|
|
- break
|
|
|
- }
|
|
|
-
|
|
|
+ // VOLUMES/MOUNTS/FILESYSTEMS
|
|
|
tmpfs := map[string]string{}
|
|
|
for _, t := range service.Tmpfs {
|
|
|
if arr := strings.SplitN(t, ":", 2); len(arr) > 1 {
|
|
|
@@ -250,39 +244,47 @@ func (s *composeService) getCreateOptions(ctx context.Context,
|
|
|
tmpfs[arr[0]] = ""
|
|
|
}
|
|
|
}
|
|
|
-
|
|
|
- var logConfig container.LogConfig
|
|
|
- if service.Logging != nil {
|
|
|
- logConfig = container.LogConfig{
|
|
|
- Type: service.Logging.Driver,
|
|
|
- Config: service.Logging.Options,
|
|
|
- }
|
|
|
+ binds, mounts, err := s.buildContainerVolumes(ctx, *p, service, inherit)
|
|
|
+ if err != nil {
|
|
|
+ return createConfigs{}, err
|
|
|
}
|
|
|
-
|
|
|
var volumesFrom []string
|
|
|
for _, v := range service.VolumesFrom {
|
|
|
if !strings.HasPrefix(v, "container:") {
|
|
|
- return nil, nil, nil, fmt.Errorf("invalid volume_from: %s", v)
|
|
|
+ return createConfigs{}, fmt.Errorf("invalid volume_from: %s", v)
|
|
|
}
|
|
|
volumesFrom = append(volumesFrom, v[len("container:"):])
|
|
|
}
|
|
|
|
|
|
+ // NETWORKING
|
|
|
links, err := s.getLinks(ctx, p.Name, service, number)
|
|
|
if err != nil {
|
|
|
- return nil, nil, nil, err
|
|
|
+ return createConfigs{}, err
|
|
|
}
|
|
|
+ networkMode, networkingConfig := defaultNetworkSettings(p, service, number, links, opts.UseNetworkAliases)
|
|
|
+ portBindings := buildContainerPortBindingOptions(service)
|
|
|
|
|
|
+ // MISC
|
|
|
+ resources := getDeployResources(service)
|
|
|
+ var logConfig container.LogConfig
|
|
|
+ if service.Logging != nil {
|
|
|
+ logConfig = container.LogConfig{
|
|
|
+ Type: service.Logging.Driver,
|
|
|
+ Config: service.Logging.Options,
|
|
|
+ }
|
|
|
+ }
|
|
|
securityOpts, unconfined, err := parseSecurityOpts(p, service.SecurityOpt)
|
|
|
if err != nil {
|
|
|
- return nil, nil, nil, err
|
|
|
+ return createConfigs{}, err
|
|
|
}
|
|
|
+
|
|
|
hostConfig := container.HostConfig{
|
|
|
- AutoRemove: autoRemove,
|
|
|
+ AutoRemove: opts.AutoRemove,
|
|
|
Binds: binds,
|
|
|
Mounts: mounts,
|
|
|
CapAdd: strslice.StrSlice(service.CapAdd),
|
|
|
CapDrop: strslice.StrSlice(service.CapDrop),
|
|
|
- NetworkMode: container.NetworkMode(service.NetworkMode),
|
|
|
+ NetworkMode: networkMode,
|
|
|
Init: service.Init,
|
|
|
IpcMode: container.IpcMode(service.Ipc),
|
|
|
CgroupnsMode: container.CgroupnsMode(service.Cgroup),
|
|
|
@@ -317,12 +319,28 @@ func (s *composeService) getCreateOptions(ctx context.Context,
|
|
|
hostConfig.ReadonlyPaths = []string{}
|
|
|
}
|
|
|
|
|
|
- return &containerConfig, &hostConfig, networkConfig, nil
|
|
|
+ cfgs := createConfigs{
|
|
|
+ Container: &containerConfig,
|
|
|
+ Host: &hostConfig,
|
|
|
+ Network: networkingConfig,
|
|
|
+ Links: links,
|
|
|
+ }
|
|
|
+ return cfgs, nil
|
|
|
+}
|
|
|
+
|
|
|
+func getAliases(project *types.Project, service types.ServiceConfig, serviceIndex int, networkKey string, useNetworkAliases bool) []string {
|
|
|
+ aliases := []string{getContainerName(project.Name, service, serviceIndex)}
|
|
|
+ if useNetworkAliases {
|
|
|
+ aliases = append(aliases, service.Name)
|
|
|
+ if cfg := service.Networks[networkKey]; cfg != nil {
|
|
|
+ aliases = append(aliases, cfg.Aliases...)
|
|
|
+ }
|
|
|
+ }
|
|
|
+ return aliases
|
|
|
}
|
|
|
|
|
|
-func (s *composeService) createNetworkConfig(p *types.Project, service types.ServiceConfig, networkID string) *network.NetworkingConfig {
|
|
|
- net := p.Networks[networkID]
|
|
|
- config := service.Networks[networkID]
|
|
|
+func createEndpointSettings(p *types.Project, service types.ServiceConfig, serviceIndex int, networkKey string, links []string, useNetworkAliases bool) *network.EndpointSettings {
|
|
|
+ config := service.Networks[networkKey]
|
|
|
var ipam *network.EndpointIPAMConfig
|
|
|
var (
|
|
|
ipv4Address string
|
|
|
@@ -337,15 +355,12 @@ func (s *composeService) createNetworkConfig(p *types.Project, service types.Ser
|
|
|
LinkLocalIPs: config.LinkLocalIPs,
|
|
|
}
|
|
|
}
|
|
|
- return &network.NetworkingConfig{
|
|
|
- EndpointsConfig: map[string]*network.EndpointSettings{
|
|
|
- net.Name: {
|
|
|
- Aliases: getAliases(service, config),
|
|
|
- IPAddress: ipv4Address,
|
|
|
- IPv6Gateway: ipv6Address,
|
|
|
- IPAMConfig: ipam,
|
|
|
- },
|
|
|
- },
|
|
|
+ return &network.EndpointSettings{
|
|
|
+ Aliases: getAliases(p, service, serviceIndex, networkKey, useNetworkAliases),
|
|
|
+ Links: links,
|
|
|
+ IPAddress: ipv4Address,
|
|
|
+ IPv6Gateway: ipv6Address,
|
|
|
+ IPAMConfig: ipam,
|
|
|
}
|
|
|
}
|
|
|
|
|
|
@@ -404,17 +419,39 @@ func (s *composeService) prepareLabels(labels types.Labels, service types.Servic
|
|
|
return labels, nil
|
|
|
}
|
|
|
|
|
|
-func getDefaultNetworkMode(project *types.Project, service types.ServiceConfig) string {
|
|
|
+// defaultNetworkSettings determines the container.NetworkMode and corresponding network.NetworkingConfig (nil if not applicable).
|
|
|
+func defaultNetworkSettings(
|
|
|
+ project *types.Project,
|
|
|
+ service types.ServiceConfig,
|
|
|
+ serviceIndex int,
|
|
|
+ links []string,
|
|
|
+ useNetworkAliases bool,
|
|
|
+) (container.NetworkMode, *network.NetworkingConfig) {
|
|
|
+ if service.NetworkMode != "" {
|
|
|
+ return container.NetworkMode(service.NetworkMode), nil
|
|
|
+ }
|
|
|
+
|
|
|
if len(project.Networks) == 0 {
|
|
|
- return "none"
|
|
|
+ return "none", nil
|
|
|
}
|
|
|
|
|
|
+ var networkKey string
|
|
|
if len(service.Networks) > 0 {
|
|
|
- name := service.NetworksByPriority()[0]
|
|
|
- return project.Networks[name].Name
|
|
|
+ networkKey = service.NetworksByPriority()[0]
|
|
|
+ } else {
|
|
|
+ networkKey = "default"
|
|
|
}
|
|
|
-
|
|
|
- return project.Networks["default"].Name
|
|
|
+ mobyNetworkName := project.Networks[networkKey].Name
|
|
|
+ epSettings := createEndpointSettings(project, service, serviceIndex, networkKey, links, useNetworkAliases)
|
|
|
+ networkConfig := &network.NetworkingConfig{
|
|
|
+ EndpointsConfig: map[string]*network.EndpointSettings{
|
|
|
+ mobyNetworkName: epSettings,
|
|
|
+ },
|
|
|
+ }
|
|
|
+ // From the Engine API docs:
|
|
|
+ // > Supported standard values are: bridge, host, none, and container:<name|id>.
|
|
|
+ // > Any other value is taken as a custom network's name to which this container should connect to.
|
|
|
+ return container.NetworkMode(mobyNetworkName), networkConfig
|
|
|
}
|
|
|
|
|
|
func getRestartPolicy(service types.ServiceConfig) container.RestartPolicy {
|
|
|
@@ -1002,14 +1039,6 @@ func buildTmpfsOptions(tmpfs *types.ServiceVolumeTmpfs) *mount.TmpfsOptions {
|
|
|
}
|
|
|
}
|
|
|
|
|
|
-func getAliases(s types.ServiceConfig, c *types.ServiceNetworkConfig) []string {
|
|
|
- aliases := []string{s.Name}
|
|
|
- if c != nil {
|
|
|
- aliases = append(aliases, c.Aliases...)
|
|
|
- }
|
|
|
- return aliases
|
|
|
-}
|
|
|
-
|
|
|
func (s *composeService) ensureNetwork(ctx context.Context, n *types.NetworkConfig) error {
|
|
|
if n.External.External {
|
|
|
return s.resolveExternalNetwork(ctx, n)
|