mirror of
https://github.com/docker/compose.git
synced 2025-07-23 21:54:40 +02:00
ACI: allow users to set DNSLabelName and deploy containers with fqdn like myapp.eastus.azurecontainers.io
Signed-off-by: Guillaume Tardif <guillaume.tardif@docker.com>
This commit is contained in:
parent
7abdb085c0
commit
701d1b834e
@ -89,7 +89,7 @@ func (cs *aciComposeService) Ps(ctx context.Context, project string) ([]compose.
|
|||||||
if isContainerVisible(container, group, false) {
|
if isContainerVisible(container, group, false) {
|
||||||
continue
|
continue
|
||||||
}
|
}
|
||||||
res = append(res, convert.ContainerGroupToServiceStatus(getContainerID(group, container), group, container))
|
res = append(res, convert.ContainerGroupToServiceStatus(getContainerID(group, container), group, container, cs.ctx.Location))
|
||||||
}
|
}
|
||||||
return res, nil
|
return res, nil
|
||||||
}
|
}
|
||||||
|
@ -63,7 +63,7 @@ func (cs *aciContainerService) List(ctx context.Context, all bool) ([]containers
|
|||||||
if isContainerVisible(container, group, all) {
|
if isContainerVisible(container, group, all) {
|
||||||
continue
|
continue
|
||||||
}
|
}
|
||||||
c := convert.ContainerGroupToContainer(getContainerID(group, container), group, container)
|
c := convert.ContainerGroupToContainer(getContainerID(group, container), group, container, cs.ctx.Location)
|
||||||
res = append(res, c)
|
res = append(res, c)
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
@ -86,6 +86,9 @@ func (cs *aciContainerService) Run(ctx context.Context, r containers.ContainerCo
|
|||||||
return err
|
return err
|
||||||
}
|
}
|
||||||
addTag(&groupDefinition, singleContainerTag)
|
addTag(&groupDefinition, singleContainerTag)
|
||||||
|
if r.DomainName != "" {
|
||||||
|
groupDefinition.ContainerGroupProperties.IPAddress.DNSNameLabel = &r.DomainName
|
||||||
|
}
|
||||||
|
|
||||||
return createACIContainers(ctx, cs.ctx, groupDefinition)
|
return createACIContainers(ctx, cs.ctx, groupDefinition)
|
||||||
}
|
}
|
||||||
@ -257,5 +260,5 @@ func (cs *aciContainerService) Inspect(ctx context.Context, containerID string)
|
|||||||
return containers.Container{}, errdefs.ErrNotFound
|
return containers.Container{}, errdefs.ErrNotFound
|
||||||
}
|
}
|
||||||
|
|
||||||
return convert.ContainerGroupToContainer(containerID, cg, cc), nil
|
return convert.ContainerGroupToContainer(containerID, cg, cc, cs.ctx.Location), nil
|
||||||
}
|
}
|
||||||
|
@ -390,7 +390,7 @@ func bytesToGb(b types.UnitBytes) float64 {
|
|||||||
}
|
}
|
||||||
|
|
||||||
// ContainerGroupToServiceStatus convert from an ACI container definition to service status
|
// ContainerGroupToServiceStatus convert from an ACI container definition to service status
|
||||||
func ContainerGroupToServiceStatus(containerID string, group containerinstance.ContainerGroup, container containerinstance.Container) compose.ServiceStatus {
|
func ContainerGroupToServiceStatus(containerID string, group containerinstance.ContainerGroup, container containerinstance.Container, region string) compose.ServiceStatus {
|
||||||
var replicas = 1
|
var replicas = 1
|
||||||
if GetStatus(container, group) != StatusRunning {
|
if GetStatus(container, group) != StatusRunning {
|
||||||
replicas = 0
|
replicas = 0
|
||||||
@ -398,14 +398,22 @@ func ContainerGroupToServiceStatus(containerID string, group containerinstance.C
|
|||||||
return compose.ServiceStatus{
|
return compose.ServiceStatus{
|
||||||
ID: containerID,
|
ID: containerID,
|
||||||
Name: *container.Name,
|
Name: *container.Name,
|
||||||
Ports: formatter.PortsToStrings(ToPorts(group.IPAddress, *container.Ports)),
|
Ports: formatter.PortsToStrings(ToPorts(group.IPAddress, *container.Ports), fqdn(group, region)),
|
||||||
Replicas: replicas,
|
Replicas: replicas,
|
||||||
Desired: 1,
|
Desired: 1,
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
func fqdn(group containerinstance.ContainerGroup, region string) string {
|
||||||
|
fqdn := ""
|
||||||
|
if group.IPAddress != nil && group.IPAddress.DNSNameLabel != nil && *group.IPAddress.DNSNameLabel != "" {
|
||||||
|
fqdn = *group.IPAddress.DNSNameLabel + "." + region + ".azurecontainer.io"
|
||||||
|
}
|
||||||
|
return fqdn
|
||||||
|
}
|
||||||
|
|
||||||
// ContainerGroupToContainer composes a Container from an ACI container definition
|
// ContainerGroupToContainer composes a Container from an ACI container definition
|
||||||
func ContainerGroupToContainer(containerID string, cg containerinstance.ContainerGroup, cc containerinstance.Container) containers.Container {
|
func ContainerGroupToContainer(containerID string, cg containerinstance.ContainerGroup, cc containerinstance.Container, region string) containers.Container {
|
||||||
memLimits := 0.
|
memLimits := 0.
|
||||||
if cc.Resources != nil &&
|
if cc.Resources != nil &&
|
||||||
cc.Resources.Limits != nil &&
|
cc.Resources.Limits != nil &&
|
||||||
@ -436,9 +444,9 @@ func ContainerGroupToContainer(containerID string, cg containerinstance.Containe
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
var config *containers.RuntimeConfig = nil
|
var config *containers.RuntimeConfig = &containers.RuntimeConfig{FQDN: fqdn(cg, region)}
|
||||||
if envVars != nil {
|
if envVars != nil {
|
||||||
config = &containers.RuntimeConfig{Env: envVars}
|
config.Env = envVars
|
||||||
}
|
}
|
||||||
c := containers.Container{
|
c := containers.Container{
|
||||||
ID: containerID,
|
ID: containerID,
|
||||||
|
@ -60,6 +60,7 @@ func TestContainerGroupToContainer(t *testing.T) {
|
|||||||
Port: to.Int32Ptr(80),
|
Port: to.Int32Ptr(80),
|
||||||
}},
|
}},
|
||||||
IP: to.StringPtr("42.42.42.42"),
|
IP: to.StringPtr("42.42.42.42"),
|
||||||
|
DNSNameLabel: to.StringPtr("myapp"),
|
||||||
},
|
},
|
||||||
OsType: "Linux",
|
OsType: "Linux",
|
||||||
},
|
},
|
||||||
@ -102,10 +103,13 @@ func TestContainerGroupToContainer(t *testing.T) {
|
|||||||
Protocol: "tcp",
|
Protocol: "tcp",
|
||||||
HostIP: "42.42.42.42",
|
HostIP: "42.42.42.42",
|
||||||
}},
|
}},
|
||||||
|
Config: &containers.RuntimeConfig{
|
||||||
|
FQDN: "myapp.eastus.azurecontainer.io",
|
||||||
|
},
|
||||||
RestartPolicyCondition: "any",
|
RestartPolicyCondition: "any",
|
||||||
}
|
}
|
||||||
|
|
||||||
container := ContainerGroupToContainer("myContainerID", myContainerGroup, myContainer)
|
container := ContainerGroupToContainer("myContainerID", myContainerGroup, myContainer, "eastus")
|
||||||
assert.DeepEqual(t, container, expectedContainer)
|
assert.DeepEqual(t, container, expectedContainer)
|
||||||
}
|
}
|
||||||
|
|
||||||
@ -143,7 +147,7 @@ func TestContainerGroupToServiceStatus(t *testing.T) {
|
|||||||
Desired: 1,
|
Desired: 1,
|
||||||
}
|
}
|
||||||
|
|
||||||
container := ContainerGroupToServiceStatus("myContainerID", myContainerGroup, myContainer)
|
container := ContainerGroupToServiceStatus("myContainerID", myContainerGroup, myContainer, "eastus")
|
||||||
assert.DeepEqual(t, container, expectedService)
|
assert.DeepEqual(t, container, expectedService)
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -57,6 +57,8 @@ type Container struct {
|
|||||||
// RuntimeConfig config of a created container
|
// RuntimeConfig config of a created container
|
||||||
type RuntimeConfig struct {
|
type RuntimeConfig struct {
|
||||||
Env map[string]string `json:",omitempty"`
|
Env map[string]string `json:",omitempty"`
|
||||||
|
// FQDN is the fqdn to use
|
||||||
|
FQDN string `json:"fqdn,omitempty"`
|
||||||
}
|
}
|
||||||
|
|
||||||
// Port represents a published port of a container
|
// Port represents a published port of a container
|
||||||
@ -91,6 +93,8 @@ type ContainerConfig struct {
|
|||||||
Environment []string
|
Environment []string
|
||||||
// Restart policy condition
|
// Restart policy condition
|
||||||
RestartPolicyCondition string
|
RestartPolicyCondition string
|
||||||
|
// DomainName Container NIS domain name
|
||||||
|
DomainName string
|
||||||
}
|
}
|
||||||
|
|
||||||
// ExecRequest contaiens configuration about an exec request
|
// ExecRequest contaiens configuration about an exec request
|
||||||
|
@ -23,13 +23,13 @@ import (
|
|||||||
"strings"
|
"strings"
|
||||||
"text/tabwriter"
|
"text/tabwriter"
|
||||||
|
|
||||||
"github.com/docker/compose-cli/utils/formatter"
|
|
||||||
|
|
||||||
"github.com/pkg/errors"
|
"github.com/pkg/errors"
|
||||||
"github.com/spf13/cobra"
|
"github.com/spf13/cobra"
|
||||||
|
|
||||||
"github.com/docker/compose-cli/api/client"
|
"github.com/docker/compose-cli/api/client"
|
||||||
|
"github.com/docker/compose-cli/api/containers"
|
||||||
formatter2 "github.com/docker/compose-cli/formatter"
|
formatter2 "github.com/docker/compose-cli/formatter"
|
||||||
|
"github.com/docker/compose-cli/utils/formatter"
|
||||||
)
|
)
|
||||||
|
|
||||||
type psOpts struct {
|
type psOpts struct {
|
||||||
@ -98,9 +98,17 @@ func runPs(ctx context.Context, opts psOpts) error {
|
|||||||
w := tabwriter.NewWriter(os.Stdout, 20, 1, 3, ' ', 0)
|
w := tabwriter.NewWriter(os.Stdout, 20, 1, 3, ' ', 0)
|
||||||
fmt.Fprintf(w, "CONTAINER ID\tIMAGE\tCOMMAND\tSTATUS\tPORTS\n")
|
fmt.Fprintf(w, "CONTAINER ID\tIMAGE\tCOMMAND\tSTATUS\tPORTS\n")
|
||||||
format := "%s\t%s\t%s\t%s\t%s\n"
|
format := "%s\t%s\t%s\t%s\t%s\n"
|
||||||
for _, c := range containers {
|
for _, container := range containers {
|
||||||
fmt.Fprintf(w, format, c.ID, c.Image, c.Command, c.Status, strings.Join(formatter.PortsToStrings(c.Ports), ", "))
|
fmt.Fprintf(w, format, container.ID, container.Image, container.Command, container.Status, strings.Join(formatter.PortsToStrings(container.Ports, fqdn(container)), ", "))
|
||||||
}
|
}
|
||||||
|
|
||||||
return w.Flush()
|
return w.Flush()
|
||||||
}
|
}
|
||||||
|
|
||||||
|
func fqdn(container containers.Container) string {
|
||||||
|
fqdn := ""
|
||||||
|
if container.Config != nil {
|
||||||
|
fqdn = container.Config.FQDN
|
||||||
|
}
|
||||||
|
return fqdn
|
||||||
|
}
|
||||||
|
@ -46,6 +46,7 @@ func Command() *cobra.Command {
|
|||||||
|
|
||||||
cmd.Flags().StringArrayVarP(&opts.Publish, "publish", "p", []string{}, "Publish a container's port(s). [HOST_PORT:]CONTAINER_PORT")
|
cmd.Flags().StringArrayVarP(&opts.Publish, "publish", "p", []string{}, "Publish a container's port(s). [HOST_PORT:]CONTAINER_PORT")
|
||||||
cmd.Flags().StringVar(&opts.Name, "name", "", "Assign a name to the container")
|
cmd.Flags().StringVar(&opts.Name, "name", "", "Assign a name to the container")
|
||||||
|
cmd.Flags().StringVar(&opts.DomainName, "domainname", "", "Container NIS domain name")
|
||||||
cmd.Flags().StringArrayVarP(&opts.Labels, "label", "l", []string{}, "Set meta data on a container")
|
cmd.Flags().StringArrayVarP(&opts.Labels, "label", "l", []string{}, "Set meta data on a container")
|
||||||
cmd.Flags().StringArrayVarP(&opts.Volumes, "volume", "v", []string{}, "Volume. Ex: storageaccount/my_share[:/absolute/path/to/target][:ro]")
|
cmd.Flags().StringArrayVarP(&opts.Volumes, "volume", "v", []string{}, "Volume. Ex: storageaccount/my_share[:/absolute/path/to/target][:ro]")
|
||||||
cmd.Flags().BoolVarP(&opts.Detach, "detach", "d", false, "Run container in background and print container ID")
|
cmd.Flags().BoolVarP(&opts.Detach, "detach", "d", false, "Run container in background and print container ID")
|
||||||
|
1
cli/cmd/run/testdata/run-help.golden
vendored
1
cli/cmd/run/testdata/run-help.golden
vendored
@ -6,6 +6,7 @@ Usage:
|
|||||||
Flags:
|
Flags:
|
||||||
--cpus float Number of CPUs (default 1)
|
--cpus float Number of CPUs (default 1)
|
||||||
-d, --detach Run container in background and print container ID
|
-d, --detach Run container in background and print container ID
|
||||||
|
--domainname string Container NIS domain name
|
||||||
-e, --env stringArray Set environment variables
|
-e, --env stringArray Set environment variables
|
||||||
-l, --label stringArray Set meta data on a container
|
-l, --label stringArray Set meta data on a container
|
||||||
-m, --memory bytes Memory limit
|
-m, --memory bytes Memory limit
|
||||||
|
@ -41,6 +41,7 @@ type Opts struct {
|
|||||||
Detach bool
|
Detach bool
|
||||||
Environment []string
|
Environment []string
|
||||||
RestartPolicyCondition string
|
RestartPolicyCondition string
|
||||||
|
DomainName string
|
||||||
}
|
}
|
||||||
|
|
||||||
// ToContainerConfig convert run options to a container configuration
|
// ToContainerConfig convert run options to a container configuration
|
||||||
@ -74,6 +75,7 @@ func (r *Opts) ToContainerConfig(image string) (containers.ContainerConfig, erro
|
|||||||
CPULimit: r.Cpus,
|
CPULimit: r.Cpus,
|
||||||
Environment: r.Environment,
|
Environment: r.Environment,
|
||||||
RestartPolicyCondition: restartPolicy,
|
RestartPolicyCondition: restartPolicy,
|
||||||
|
DomainName: r.DomainName,
|
||||||
}, nil
|
}, nil
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -335,18 +335,19 @@ func lines(output string) []string {
|
|||||||
|
|
||||||
func TestContainerRunAttached(t *testing.T) {
|
func TestContainerRunAttached(t *testing.T) {
|
||||||
c := NewParallelE2eCLI(t, binDir)
|
c := NewParallelE2eCLI(t, binDir)
|
||||||
_, _ = setupTestResourceGroup(t, c)
|
_, groupID := setupTestResourceGroup(t, c)
|
||||||
|
|
||||||
// Used in subtests
|
// Used in subtests
|
||||||
var (
|
var (
|
||||||
container string
|
container string = "test-container"
|
||||||
endpoint string
|
endpoint string
|
||||||
|
followLogsProcess *icmd.Result
|
||||||
)
|
)
|
||||||
|
|
||||||
container = "test-container"
|
|
||||||
|
|
||||||
var followLogsProcess *icmd.Result
|
|
||||||
t.Run("run attached limits", func(t *testing.T) {
|
t.Run("run attached limits", func(t *testing.T) {
|
||||||
|
dnsLabelName := "nginx-" + groupID
|
||||||
|
fqdn := dnsLabelName + "." + location + ".azurecontainer.io"
|
||||||
|
|
||||||
cmd := c.NewDockerCmd(
|
cmd := c.NewDockerCmd(
|
||||||
"run",
|
"run",
|
||||||
"--name", container,
|
"--name", container,
|
||||||
@ -354,15 +355,17 @@ func TestContainerRunAttached(t *testing.T) {
|
|||||||
"--memory", "0.1G", "--cpus", "0.1",
|
"--memory", "0.1G", "--cpus", "0.1",
|
||||||
"-p", "80:80",
|
"-p", "80:80",
|
||||||
"nginx",
|
"nginx",
|
||||||
|
"--domainname",
|
||||||
|
dnsLabelName,
|
||||||
)
|
)
|
||||||
followLogsProcess = icmd.StartCmd(cmd)
|
followLogsProcess = icmd.StartCmd(cmd)
|
||||||
|
|
||||||
checkRunning := func(t poll.LogT) poll.Result {
|
checkRunning := func(t poll.LogT) poll.Result {
|
||||||
res := c.RunDockerOrExitError("inspect", container)
|
res := c.RunDockerOrExitError("inspect", container)
|
||||||
if res.ExitCode == 0 {
|
if res.ExitCode == 0 && strings.Contains(res.Stdout(), `"Status": "Running"`) {
|
||||||
return poll.Success()
|
return poll.Success()
|
||||||
}
|
}
|
||||||
return poll.Continue("waiting for container to be running")
|
return poll.Continue("waiting for container to be running, current inspect result: \n%s", res.Combined())
|
||||||
}
|
}
|
||||||
poll.WaitOn(t, checkRunning, poll.WithDelay(5*time.Second), poll.WithTimeout(60*time.Second))
|
poll.WaitOn(t, checkRunning, poll.WithDelay(5*time.Second), poll.WithTimeout(60*time.Second))
|
||||||
|
|
||||||
@ -380,7 +383,8 @@ func TestContainerRunAttached(t *testing.T) {
|
|||||||
assert.Assert(t, len(port.HostIP) > 0)
|
assert.Assert(t, len(port.HostIP) > 0)
|
||||||
assert.Equal(t, port.ContainerPort, uint32(80))
|
assert.Equal(t, port.ContainerPort, uint32(80))
|
||||||
assert.Equal(t, port.HostPort, uint32(80))
|
assert.Equal(t, port.HostPort, uint32(80))
|
||||||
endpoint = fmt.Sprintf("http://%s:%d", port.HostIP, port.HostPort)
|
assert.Equal(t, containerInspect.Config.FQDN, fqdn)
|
||||||
|
endpoint = fmt.Sprintf("http://%s:%d", fqdn, port.HostPort)
|
||||||
|
|
||||||
assert.Assert(t, !strings.Contains(followLogsProcess.Stdout(), "/test"))
|
assert.Assert(t, !strings.Contains(followLogsProcess.Stdout(), "/test"))
|
||||||
checkRequest := func(t poll.LogT) poll.Result {
|
checkRequest := func(t poll.LogT) poll.Result {
|
||||||
|
@ -31,7 +31,7 @@ type portGroup struct {
|
|||||||
}
|
}
|
||||||
|
|
||||||
// PortsToStrings returns a human readable published ports
|
// PortsToStrings returns a human readable published ports
|
||||||
func PortsToStrings(ports []containers.Port) []string {
|
func PortsToStrings(ports []containers.Port, fqdn string) []string {
|
||||||
groupMap := make(map[string]*portGroup)
|
groupMap := make(map[string]*portGroup)
|
||||||
var (
|
var (
|
||||||
result []string
|
result []string
|
||||||
@ -49,6 +49,9 @@ func PortsToStrings(ports []containers.Port) []string {
|
|||||||
if port.HostIP != "" {
|
if port.HostIP != "" {
|
||||||
hostIP = port.HostIP
|
hostIP = port.HostIP
|
||||||
}
|
}
|
||||||
|
if fqdn != "" {
|
||||||
|
hostIP = fqdn
|
||||||
|
}
|
||||||
|
|
||||||
if port.HostPort != port.ContainerPort {
|
if port.HostPort != port.ContainerPort {
|
||||||
hostMappings = append(hostMappings, fmt.Sprintf("%s:%d->%d/%s", hostIP, port.HostPort, port.ContainerPort, port.Protocol))
|
hostMappings = append(hostMappings, fmt.Sprintf("%s:%d->%d/%s", hostIP, port.HostPort, port.ContainerPort, port.Protocol))
|
||||||
|
@ -24,7 +24,7 @@ import (
|
|||||||
"github.com/docker/compose-cli/cli/options/run"
|
"github.com/docker/compose-cli/cli/options/run"
|
||||||
)
|
)
|
||||||
|
|
||||||
func TestDisplayPorts(t *testing.T) {
|
func TestDisplayPortsNoDomainname(t *testing.T) {
|
||||||
testCases := []struct {
|
testCases := []struct {
|
||||||
name string
|
name string
|
||||||
in []string
|
in []string
|
||||||
@ -70,8 +70,19 @@ func TestDisplayPorts(t *testing.T) {
|
|||||||
containerConfig, err := runOpts.ToContainerConfig("test")
|
containerConfig, err := runOpts.ToContainerConfig("test")
|
||||||
assert.NilError(t, err)
|
assert.NilError(t, err)
|
||||||
|
|
||||||
out := PortsToStrings(containerConfig.Ports)
|
out := PortsToStrings(containerConfig.Ports, "")
|
||||||
assert.DeepEqual(t, testCase.expected, out)
|
assert.DeepEqual(t, testCase.expected, out)
|
||||||
})
|
})
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
func TestDisplayPortsWithDomainname(t *testing.T) {
|
||||||
|
runOpts := run.Opts{
|
||||||
|
Publish: []string{"80"},
|
||||||
|
}
|
||||||
|
containerConfig, err := runOpts.ToContainerConfig("test")
|
||||||
|
assert.NilError(t, err)
|
||||||
|
|
||||||
|
out := PortsToStrings(containerConfig.Ports, "mydomain.westus.azurecontainner.io")
|
||||||
|
assert.DeepEqual(t, []string{"mydomain.westus.azurecontainner.io:80->80/tcp"}, out)
|
||||||
|
}
|
||||||
|
Loading…
x
Reference in New Issue
Block a user