Implement --domainname flag on compose up, also defining compose extension "x-aci-domain-name" to store ACI DNSLabelName.

Signed-off-by: Guillaume Tardif <guillaume.tardif@docker.com>
This commit is contained in:
Guillaume Tardif 2020-09-21 17:05:49 +02:00
parent 268c02523a
commit 334ebf5f75
5 changed files with 67 additions and 26 deletions

View File

@ -43,8 +43,10 @@ const (
StatusRunning = "Running"
// ComposeDNSSidecarName name of the dns sidecar container
ComposeDNSSidecarName = "aci--dns--sidecar"
dnsSidecarImage = "busybox:1.31.1"
// ExtensionDomainName compose extension to set ACI DNS label name
ExtensionDomainName = "x-aci-domain-name"
dnsSidecarImage = "busybox:1.31.1"
azureFileDriverName = "azure_file"
volumeDriveroptsShareNameKey = "share_name"
volumeDriveroptsAccountNameKey = "storage_account_name"
@ -103,26 +105,16 @@ func ToContainerGroup(ctx context.Context, aciContext store.AciContext, p types.
return containerinstance.ContainerGroup{}, errors.New("ACI integration does not support labels in compose applications")
}
if service.Ports != nil {
var containerPorts []containerinstance.ContainerPort
for _, portConfig := range service.Ports {
if portConfig.Published != 0 && portConfig.Published != portConfig.Target {
msg := fmt.Sprintf("Port mapping is not supported with ACI, cannot map port %d to %d for container %s",
portConfig.Published, portConfig.Target, service.Name)
return groupDefinition, errors.New(msg)
}
portNumber := int32(portConfig.Target)
containerPorts = append(containerPorts, containerinstance.ContainerPort{
Port: to.Int32Ptr(portNumber),
})
groupPorts = append(groupPorts, containerinstance.Port{
Port: to.Int32Ptr(portNumber),
Protocol: containerinstance.TCP,
})
containerPorts, serviceGroupPorts, dnsLabelName, err := convertPortsToAci(service, p)
if err != nil {
return groupDefinition, err
}
containerDefinition.ContainerProperties.Ports = &containerPorts
groupPorts = append(groupPorts, serviceGroupPorts...)
groupDefinition.ContainerGroupProperties.IPAddress = &containerinstance.IPAddress{
Type: containerinstance.Public,
Ports: &groupPorts,
Type: containerinstance.Public,
Ports: &groupPorts,
DNSNameLabel: dnsLabelName,
}
}
@ -137,6 +129,35 @@ func ToContainerGroup(ctx context.Context, aciContext store.AciContext, p types.
return groupDefinition, nil
}
func convertPortsToAci(service serviceConfigAciHelper, p types.Project) ([]containerinstance.ContainerPort, []containerinstance.Port, *string, error) {
var groupPorts []containerinstance.Port
var containerPorts []containerinstance.ContainerPort
for _, portConfig := range service.Ports {
if portConfig.Published != 0 && portConfig.Published != portConfig.Target {
msg := fmt.Sprintf("Port mapping is not supported with ACI, cannot map port %d to %d for container %s",
portConfig.Published, portConfig.Target, service.Name)
return nil, nil, nil, errors.New(msg)
}
portNumber := int32(portConfig.Target)
containerPorts = append(containerPorts, containerinstance.ContainerPort{
Port: to.Int32Ptr(portNumber),
})
groupPorts = append(groupPorts, containerinstance.Port{
Port: to.Int32Ptr(portNumber),
Protocol: containerinstance.TCP,
})
}
var dnsLabelName *string = nil
if extension, ok := p.Extensions[ExtensionDomainName]; ok {
domain, ok := extension.(string)
if !ok {
return nil, nil, nil, fmt.Errorf("could not read %s compose extension as string", ExtensionDomainName)
}
dnsLabelName = &domain
}
return containerPorts, groupPorts, dnsLabelName, nil
}
func getDNSSidecar(containers []containerinstance.Container) containerinstance.Container {
var commands []string
for _, container := range containers {

View File

@ -29,6 +29,7 @@ import (
type composeOptions struct {
Name string
DomainName string
WorkingDir string
ConfigPaths []string
Environment []string
@ -60,7 +61,7 @@ func (o *composeOptions) toProjectOptions() (*cli.ProjectOptions, error) {
}
// Command returns the compose command with its child commands
func Command() *cobra.Command {
func Command(contextType string) *cobra.Command {
command := &cobra.Command{
Short: "Docker Compose",
Use: "compose",
@ -70,7 +71,7 @@ func Command() *cobra.Command {
}
command.AddCommand(
upCommand(),
upCommand(contextType),
downCommand(),
psCommand(),
listCommand(),

View File

@ -20,14 +20,15 @@ import (
"context"
"github.com/compose-spec/compose-go/cli"
"github.com/spf13/cobra"
aciconvert "github.com/docker/compose-cli/aci/convert"
"github.com/docker/compose-cli/api/client"
"github.com/docker/compose-cli/context/store"
"github.com/docker/compose-cli/progress"
)
func upCommand() *cobra.Command {
func upCommand(contextType string) *cobra.Command {
opts := composeOptions{}
upCmd := &cobra.Command{
Use: "up",
@ -40,6 +41,11 @@ func upCommand() *cobra.Command {
upCmd.Flags().StringArrayVarP(&opts.ConfigPaths, "file", "f", []string{}, "Compose configuration files")
upCmd.Flags().StringArrayVarP(&opts.Environment, "environment", "e", []string{}, "Environment variables")
upCmd.Flags().BoolP("detach", "d", true, " Detached mode: Run containers in the background")
if contextType == store.AciContextType {
upCmd.Flags().StringVar(&opts.DomainName, "domainname", "", "Container NIS domain name")
}
return upCmd
}
@ -55,6 +61,9 @@ func runUp(ctx context.Context, opts composeOptions) error {
return "", err
}
project, err := cli.ProjectFromOptions(options)
if opts.DomainName != "" {
project.Extensions = map[string]interface{}{aciconvert.ExtensionDomainName: opts.DomainName}
}
if err != nil {
return "", err
}

View File

@ -126,7 +126,6 @@ func main() {
cmd.StopCommand(),
cmd.KillCommand(),
cmd.SecretCommand(),
compose.Command(),
// Place holders
cmd.EcsCommand(),
@ -179,7 +178,10 @@ func main() {
ctype = cc.Type()
}
root.AddCommand(run.Command(ctype))
root.AddCommand(
run.Command(ctype),
compose.Command(ctype),
)
if ctype == store.AciContextType {
// we can also pass ctype as a parameter to the volume command and customize subcommands, flags, etc. when we have other backend implementations

View File

@ -453,7 +453,7 @@ func TestContainerRunAttached(t *testing.T) {
func TestComposeUpUpdate(t *testing.T) {
c := NewParallelE2eCLI(t, binDir)
_, _ = setupTestResourceGroup(t, c)
_, groupID := setupTestResourceGroup(t, c)
const (
composeFile = "../composefiles/aci-demo/aci_demo_port.yaml"
@ -465,8 +465,11 @@ func TestComposeUpUpdate(t *testing.T) {
)
t.Run("compose up", func(t *testing.T) {
dnsLabelName := "nginx-" + groupID
fqdn := dnsLabelName + "." + location + ".azurecontainer.io"
// Name of Compose project is taken from current folder "acie2e"
c.RunDockerCmd("compose", "up", "-f", composeFile)
c.RunDockerCmd("compose", "up", "-f", composeFile, "--domainname", dnsLabelName)
res := c.RunDockerCmd("ps")
out := lines(res.Stdout())
// Check three containers are running
@ -493,6 +496,11 @@ func TestComposeUpUpdate(t *testing.T) {
b, err := ioutil.ReadAll(r.Body)
assert.NilError(t, err)
assert.Assert(t, strings.Contains(string(b), `"word":`))
endpoint = fmt.Sprintf("http://%s:%d", fqdn, containerInspect.Ports[0].HostPort)
r, err = HTTPGetWithRetry(endpoint+"/words/noun", 3)
assert.NilError(t, err)
assert.Equal(t, r.StatusCode, http.StatusOK)
})
t.Run("compose ps", func(t *testing.T) {