mirror of https://github.com/docker/compose.git
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) {
|
||||
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
|
||||
}
|
||||
|
|
|
@ -63,7 +63,7 @@ func (cs *aciContainerService) List(ctx context.Context, all bool) ([]containers
|
|||
if isContainerVisible(container, group, all) {
|
||||
continue
|
||||
}
|
||||
c := convert.ContainerGroupToContainer(getContainerID(group, container), group, container)
|
||||
c := convert.ContainerGroupToContainer(getContainerID(group, container), group, container, cs.ctx.Location)
|
||||
res = append(res, c)
|
||||
}
|
||||
}
|
||||
|
@ -86,6 +86,9 @@ func (cs *aciContainerService) Run(ctx context.Context, r containers.ContainerCo
|
|||
return err
|
||||
}
|
||||
addTag(&groupDefinition, singleContainerTag)
|
||||
if r.DomainName != "" {
|
||||
groupDefinition.ContainerGroupProperties.IPAddress.DNSNameLabel = &r.DomainName
|
||||
}
|
||||
|
||||
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 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
|
||||
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
|
||||
if GetStatus(container, group) != StatusRunning {
|
||||
replicas = 0
|
||||
|
@ -398,14 +398,22 @@ func ContainerGroupToServiceStatus(containerID string, group containerinstance.C
|
|||
return compose.ServiceStatus{
|
||||
ID: containerID,
|
||||
Name: *container.Name,
|
||||
Ports: formatter.PortsToStrings(ToPorts(group.IPAddress, *container.Ports)),
|
||||
Ports: formatter.PortsToStrings(ToPorts(group.IPAddress, *container.Ports), fqdn(group, region)),
|
||||
Replicas: replicas,
|
||||
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
|
||||
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.
|
||||
if cc.Resources != 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 {
|
||||
config = &containers.RuntimeConfig{Env: envVars}
|
||||
config.Env = envVars
|
||||
}
|
||||
c := containers.Container{
|
||||
ID: containerID,
|
||||
|
|
|
@ -59,7 +59,8 @@ func TestContainerGroupToContainer(t *testing.T) {
|
|||
Ports: &[]containerinstance.Port{{
|
||||
Port: to.Int32Ptr(80),
|
||||
}},
|
||||
IP: to.StringPtr("42.42.42.42"),
|
||||
IP: to.StringPtr("42.42.42.42"),
|
||||
DNSNameLabel: to.StringPtr("myapp"),
|
||||
},
|
||||
OsType: "Linux",
|
||||
},
|
||||
|
@ -102,10 +103,13 @@ func TestContainerGroupToContainer(t *testing.T) {
|
|||
Protocol: "tcp",
|
||||
HostIP: "42.42.42.42",
|
||||
}},
|
||||
Config: &containers.RuntimeConfig{
|
||||
FQDN: "myapp.eastus.azurecontainer.io",
|
||||
},
|
||||
RestartPolicyCondition: "any",
|
||||
}
|
||||
|
||||
container := ContainerGroupToContainer("myContainerID", myContainerGroup, myContainer)
|
||||
container := ContainerGroupToContainer("myContainerID", myContainerGroup, myContainer, "eastus")
|
||||
assert.DeepEqual(t, container, expectedContainer)
|
||||
}
|
||||
|
||||
|
@ -143,7 +147,7 @@ func TestContainerGroupToServiceStatus(t *testing.T) {
|
|||
Desired: 1,
|
||||
}
|
||||
|
||||
container := ContainerGroupToServiceStatus("myContainerID", myContainerGroup, myContainer)
|
||||
container := ContainerGroupToServiceStatus("myContainerID", myContainerGroup, myContainer, "eastus")
|
||||
assert.DeepEqual(t, container, expectedService)
|
||||
}
|
||||
|
||||
|
|
|
@ -57,6 +57,8 @@ type Container struct {
|
|||
// RuntimeConfig config of a created container
|
||||
type RuntimeConfig struct {
|
||||
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
|
||||
|
@ -91,6 +93,8 @@ type ContainerConfig struct {
|
|||
Environment []string
|
||||
// Restart policy condition
|
||||
RestartPolicyCondition string
|
||||
// DomainName Container NIS domain name
|
||||
DomainName string
|
||||
}
|
||||
|
||||
// ExecRequest contaiens configuration about an exec request
|
||||
|
|
|
@ -23,13 +23,13 @@ import (
|
|||
"strings"
|
||||
"text/tabwriter"
|
||||
|
||||
"github.com/docker/compose-cli/utils/formatter"
|
||||
|
||||
"github.com/pkg/errors"
|
||||
"github.com/spf13/cobra"
|
||||
|
||||
"github.com/docker/compose-cli/api/client"
|
||||
"github.com/docker/compose-cli/api/containers"
|
||||
formatter2 "github.com/docker/compose-cli/formatter"
|
||||
"github.com/docker/compose-cli/utils/formatter"
|
||||
)
|
||||
|
||||
type psOpts struct {
|
||||
|
@ -98,9 +98,17 @@ func runPs(ctx context.Context, opts psOpts) error {
|
|||
w := tabwriter.NewWriter(os.Stdout, 20, 1, 3, ' ', 0)
|
||||
fmt.Fprintf(w, "CONTAINER ID\tIMAGE\tCOMMAND\tSTATUS\tPORTS\n")
|
||||
format := "%s\t%s\t%s\t%s\t%s\n"
|
||||
for _, c := range containers {
|
||||
fmt.Fprintf(w, format, c.ID, c.Image, c.Command, c.Status, strings.Join(formatter.PortsToStrings(c.Ports), ", "))
|
||||
for _, container := range containers {
|
||||
fmt.Fprintf(w, format, container.ID, container.Image, container.Command, container.Status, strings.Join(formatter.PortsToStrings(container.Ports, fqdn(container)), ", "))
|
||||
}
|
||||
|
||||
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().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.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")
|
||||
|
|
|
@ -6,6 +6,7 @@ Usage:
|
|||
Flags:
|
||||
--cpus float Number of CPUs (default 1)
|
||||
-d, --detach Run container in background and print container ID
|
||||
--domainname string Container NIS domain name
|
||||
-e, --env stringArray Set environment variables
|
||||
-l, --label stringArray Set meta data on a container
|
||||
-m, --memory bytes Memory limit
|
||||
|
|
|
@ -41,6 +41,7 @@ type Opts struct {
|
|||
Detach bool
|
||||
Environment []string
|
||||
RestartPolicyCondition string
|
||||
DomainName string
|
||||
}
|
||||
|
||||
// ToContainerConfig convert run options to a container configuration
|
||||
|
@ -74,6 +75,7 @@ func (r *Opts) ToContainerConfig(image string) (containers.ContainerConfig, erro
|
|||
CPULimit: r.Cpus,
|
||||
Environment: r.Environment,
|
||||
RestartPolicyCondition: restartPolicy,
|
||||
DomainName: r.DomainName,
|
||||
}, nil
|
||||
}
|
||||
|
||||
|
|
|
@ -335,18 +335,19 @@ func lines(output string) []string {
|
|||
|
||||
func TestContainerRunAttached(t *testing.T) {
|
||||
c := NewParallelE2eCLI(t, binDir)
|
||||
_, _ = setupTestResourceGroup(t, c)
|
||||
_, groupID := setupTestResourceGroup(t, c)
|
||||
|
||||
// Used in subtests
|
||||
var (
|
||||
container string
|
||||
endpoint string
|
||||
container string = "test-container"
|
||||
endpoint string
|
||||
followLogsProcess *icmd.Result
|
||||
)
|
||||
|
||||
container = "test-container"
|
||||
|
||||
var followLogsProcess *icmd.Result
|
||||
t.Run("run attached limits", func(t *testing.T) {
|
||||
dnsLabelName := "nginx-" + groupID
|
||||
fqdn := dnsLabelName + "." + location + ".azurecontainer.io"
|
||||
|
||||
cmd := c.NewDockerCmd(
|
||||
"run",
|
||||
"--name", container,
|
||||
|
@ -354,15 +355,17 @@ func TestContainerRunAttached(t *testing.T) {
|
|||
"--memory", "0.1G", "--cpus", "0.1",
|
||||
"-p", "80:80",
|
||||
"nginx",
|
||||
"--domainname",
|
||||
dnsLabelName,
|
||||
)
|
||||
followLogsProcess = icmd.StartCmd(cmd)
|
||||
|
||||
checkRunning := func(t poll.LogT) poll.Result {
|
||||
res := c.RunDockerOrExitError("inspect", container)
|
||||
if res.ExitCode == 0 {
|
||||
if res.ExitCode == 0 && strings.Contains(res.Stdout(), `"Status": "Running"`) {
|
||||
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))
|
||||
|
||||
|
@ -380,7 +383,8 @@ func TestContainerRunAttached(t *testing.T) {
|
|||
assert.Assert(t, len(port.HostIP) > 0)
|
||||
assert.Equal(t, port.ContainerPort, 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"))
|
||||
checkRequest := func(t poll.LogT) poll.Result {
|
||||
|
|
|
@ -31,7 +31,7 @@ type portGroup struct {
|
|||
}
|
||||
|
||||
// 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)
|
||||
var (
|
||||
result []string
|
||||
|
@ -49,6 +49,9 @@ func PortsToStrings(ports []containers.Port) []string {
|
|||
if port.HostIP != "" {
|
||||
hostIP = port.HostIP
|
||||
}
|
||||
if fqdn != "" {
|
||||
hostIP = fqdn
|
||||
}
|
||||
|
||||
if port.HostPort != port.ContainerPort {
|
||||
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"
|
||||
)
|
||||
|
||||
func TestDisplayPorts(t *testing.T) {
|
||||
func TestDisplayPortsNoDomainname(t *testing.T) {
|
||||
testCases := []struct {
|
||||
name string
|
||||
in []string
|
||||
|
@ -70,8 +70,19 @@ func TestDisplayPorts(t *testing.T) {
|
|||
containerConfig, err := runOpts.ToContainerConfig("test")
|
||||
assert.NilError(t, err)
|
||||
|
||||
out := PortsToStrings(containerConfig.Ports)
|
||||
out := PortsToStrings(containerConfig.Ports, "")
|
||||
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…
Reference in New Issue