Skip to content
This repository was archived by the owner on Nov 27, 2023. It is now read-only.

Commit daf7061

Browse files
authored
Merge pull request #244 from docker/aci_dns_sidecar
Aci dns sidecar
2 parents a72ba8a + 8bfe0c5 commit daf7061

File tree

6 files changed

+162
-135
lines changed

6 files changed

+162
-135
lines changed

azure/aci.go

Lines changed: 0 additions & 61 deletions
Original file line numberDiff line numberDiff line change
@@ -20,9 +20,7 @@ import (
2020
"context"
2121
"fmt"
2222
"io"
23-
"io/ioutil"
2423
"net/http"
25-
"strings"
2624
"time"
2725

2826
"github.com/Azure/azure-sdk-for-go/services/containerinstance/mgmt/2018-10-01/containerinstance"
@@ -103,10 +101,6 @@ func createOrUpdateACIContainers(ctx context.Context, aciContext store.AciContex
103101
return err
104102
}
105103

106-
containerGroup, err := future.Result(containerGroupsClient)
107-
if err != nil {
108-
return err
109-
}
110104
for _, c := range *groupDefinition.Containers {
111105
w.Event(progress.Event{
112106
ID: *c.Name,
@@ -115,30 +109,6 @@ func createOrUpdateACIContainers(ctx context.Context, aciContext store.AciContex
115109
})
116110
}
117111

118-
if len(*containerGroup.Containers) > 1 {
119-
var commands []string
120-
for _, container := range *containerGroup.Containers {
121-
commands = append(commands, fmt.Sprintf("echo 127.0.0.1 %s >> /etc/hosts", *container.Name))
122-
}
123-
commands = append(commands, "exit")
124-
125-
containers := *containerGroup.Containers
126-
container := containers[0]
127-
response, err := execACIContainer(ctx, aciContext, "/bin/sh", *containerGroup.Name, *container.Name)
128-
if err != nil {
129-
return err
130-
}
131-
132-
if err = execCommands(
133-
ctx,
134-
*response.WebSocketURI,
135-
*response.Password,
136-
commands,
137-
); err != nil {
138-
return err
139-
}
140-
}
141-
142112
return err
143113
}
144114

@@ -188,37 +158,6 @@ func getTermSize() (*int32, *int32) {
188158
return to.Int32Ptr(int32(rows)), to.Int32Ptr(int32(cols))
189159
}
190160

191-
type commandSender struct {
192-
commands string
193-
}
194-
195-
func (cs *commandSender) Read(p []byte) (int, error) {
196-
if len(cs.commands) == 0 {
197-
return 0, io.EOF
198-
}
199-
200-
var command string
201-
if len(p) >= len(cs.commands) {
202-
command = cs.commands
203-
cs.commands = ""
204-
} else {
205-
command = cs.commands[:len(p)]
206-
cs.commands = cs.commands[len(p):]
207-
}
208-
209-
copy(p, command)
210-
211-
return len(command), nil
212-
}
213-
214-
func execCommands(ctx context.Context, address string, password string, commands []string) error {
215-
writer := ioutil.Discard
216-
reader := &commandSender{
217-
commands: strings.Join(commands, "\n"),
218-
}
219-
return exec(ctx, address, password, reader, writer)
220-
}
221-
222161
func exec(ctx context.Context, address string, password string, reader io.Reader, writer io.Writer) error {
223162
conn, _, _, err := ws.DefaultDialer.Dial(ctx, address)
224163
if err != nil {

azure/backend.go

Lines changed: 4 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -129,6 +129,10 @@ func (cs *aciContainerService) List(ctx context.Context, _ bool) ([]containers.C
129129

130130
for _, container := range *group.Containers {
131131
var containerID string
132+
// don't list sidecar container
133+
if *container.Name == convert.ComposeDNSSidecarName {
134+
continue
135+
}
132136
if *container.Name == singleContainerName {
133137
containerID = *containerGroup.Name
134138
} else {

azure/backend_test.go

Lines changed: 0 additions & 58 deletions
Original file line numberDiff line numberDiff line change
@@ -19,14 +19,9 @@ package azure
1919
import (
2020
"testing"
2121

22-
"github.com/Azure/azure-sdk-for-go/profiles/latest/containerinstance/mgmt/containerinstance"
23-
"github.com/Azure/go-autorest/autorest/to"
2422
"github.com/stretchr/testify/suite"
2523

2624
. "github.com/onsi/gomega"
27-
28-
"github.com/docker/api/azure/convert"
29-
"github.com/docker/api/containers"
3025
)
3126

3227
type BackendSuiteTest struct {
@@ -51,56 +46,3 @@ func TestBackendSuite(t *testing.T) {
5146
RegisterTestingT(t)
5247
suite.Run(t, new(BackendSuiteTest))
5348
}
54-
55-
func TestContainerGroupToContainer(t *testing.T) {
56-
myContainerGroup := containerinstance.ContainerGroup{
57-
ContainerGroupProperties: &containerinstance.ContainerGroupProperties{
58-
IPAddress: &containerinstance.IPAddress{
59-
Ports: &[]containerinstance.Port{{
60-
Port: to.Int32Ptr(80),
61-
}},
62-
IP: to.StringPtr("42.42.42.42"),
63-
},
64-
},
65-
}
66-
myContainer := containerinstance.Container{
67-
Name: to.StringPtr("myContainerID"),
68-
ContainerProperties: &containerinstance.ContainerProperties{
69-
Image: to.StringPtr("sha256:666"),
70-
Command: to.StringSlicePtr([]string{"mycommand"}),
71-
Ports: &[]containerinstance.ContainerPort{{
72-
Port: to.Int32Ptr(80),
73-
}},
74-
EnvironmentVariables: nil,
75-
InstanceView: &containerinstance.ContainerPropertiesInstanceView{
76-
RestartCount: nil,
77-
CurrentState: &containerinstance.ContainerState{
78-
State: to.StringPtr("Running"),
79-
},
80-
},
81-
Resources: &containerinstance.ResourceRequirements{
82-
Limits: &containerinstance.ResourceLimits{
83-
MemoryInGB: to.Float64Ptr(9),
84-
},
85-
},
86-
},
87-
}
88-
89-
var expectedContainer = containers.Container{
90-
ID: "myContainerID",
91-
Status: "Running",
92-
Image: "sha256:666",
93-
Command: "mycommand",
94-
MemoryLimit: 9,
95-
Ports: []containers.Port{{
96-
HostPort: uint32(80),
97-
ContainerPort: uint32(80),
98-
Protocol: "tcp",
99-
HostIP: "42.42.42.42",
100-
}},
101-
}
102-
103-
container, err := convert.ContainerGroupToContainer("myContainerID", myContainerGroup, myContainer)
104-
Expect(err).To(BeNil())
105-
Expect(container).To(Equal(expectedContainer))
106-
}

azure/convert/convert.go

Lines changed: 38 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -33,6 +33,10 @@ import (
3333
)
3434

3535
const (
36+
// ComposeDNSSidecarName name of the dns sidecar container
37+
ComposeDNSSidecarName = "aci--dns--sidecar"
38+
dnsSidecarImage = "busybox:1.31.1"
39+
3640
azureFileDriverName = "azure_file"
3741
volumeDriveroptsShareNameKey = "share_name"
3842
volumeDriveroptsAccountNameKey = "storage_account_name"
@@ -110,10 +114,44 @@ func ToContainerGroup(aciContext store.AciContext, p compose.Project) (container
110114

111115
containers = append(containers, containerDefinition)
112116
}
117+
if len(containers) > 1 {
118+
dnsSideCar := getDNSSidecar(containers)
119+
containers = append(containers, dnsSideCar)
120+
}
113121
groupDefinition.ContainerGroupProperties.Containers = &containers
122+
114123
return groupDefinition, nil
115124
}
116125

126+
func getDNSSidecar(containers []containerinstance.Container) containerinstance.Container {
127+
var commands []string
128+
for _, container := range containers {
129+
commands = append(commands, fmt.Sprintf("echo 127.0.0.1 %s >> /etc/hosts", *container.Name))
130+
}
131+
// ACI restart policy is currently at container group level, cannot let the sidecar terminate quietly once /etc/hosts has been edited
132+
// Pricing is done at the container group level so letting the sidecar container "sleep" should not impact the price for the whole group
133+
commands = append(commands, "sleep infinity")
134+
alpineCmd := []string{"sh", "-c", strings.Join(commands, ";")}
135+
dnsSideCar := containerinstance.Container{
136+
Name: to.StringPtr(ComposeDNSSidecarName),
137+
ContainerProperties: &containerinstance.ContainerProperties{
138+
Image: to.StringPtr(dnsSidecarImage),
139+
Command: &alpineCmd,
140+
Resources: &containerinstance.ResourceRequirements{
141+
Limits: &containerinstance.ResourceLimits{
142+
MemoryInGB: to.Float64Ptr(0.1), // "The memory requirement should be in incrememts of 0.1 GB."
143+
CPU: to.Float64Ptr(0.01), // "The CPU requirement should be in incrememts of 0.01."
144+
},
145+
Requests: &containerinstance.ResourceRequests{
146+
MemoryInGB: to.Float64Ptr(0.1),
147+
CPU: to.Float64Ptr(0.01),
148+
},
149+
},
150+
},
151+
}
152+
return dnsSideCar
153+
}
154+
117155
type projectAciHelper compose.Project
118156

119157
func (p projectAciHelper) getAciSecretVolumes() ([]containerinstance.Volume, error) {

azure/convert/convert_test.go

Lines changed: 119 additions & 15 deletions
Original file line numberDiff line numberDiff line change
@@ -19,44 +19,148 @@ package convert
1919
import (
2020
"testing"
2121

22+
"github.com/Azure/azure-sdk-for-go/profiles/latest/containerinstance/mgmt/containerinstance"
23+
"github.com/Azure/go-autorest/autorest/to"
24+
"github.com/compose-spec/compose-go/types"
25+
2226
"github.com/docker/api/compose"
27+
"github.com/docker/api/containers"
2328
"github.com/docker/api/context/store"
2429

30+
. "github.com/onsi/gomega"
2531
"github.com/stretchr/testify/require"
2632
"github.com/stretchr/testify/suite"
2733
)
2834

29-
const (
30-
projectName = "TEST"
31-
expectedProjectName = "test"
32-
)
33-
3435
type ConvertTestSuite struct {
3536
suite.Suite
36-
ctx store.AciContext
37-
project compose.Project
37+
ctx store.AciContext
3838
}
3939

4040
func (suite *ConvertTestSuite) BeforeTest(suiteName, testName string) {
41-
ctx := store.AciContext{
41+
suite.ctx = store.AciContext{
4242
SubscriptionID: "subID",
4343
ResourceGroup: "rg",
4444
Location: "eu",
4545
}
46+
}
47+
48+
func (suite *ConvertTestSuite) TestProjectName() {
4649
project := compose.Project{
47-
Name: projectName,
50+
Name: "TEST",
51+
}
52+
containerGroup, err := ToContainerGroup(suite.ctx, project)
53+
require.NoError(suite.T(), err)
54+
require.Equal(suite.T(), *containerGroup.Name, "test")
55+
}
56+
57+
func (suite *ConvertTestSuite) TestContainerGroupToContainer() {
58+
myContainerGroup := containerinstance.ContainerGroup{
59+
ContainerGroupProperties: &containerinstance.ContainerGroupProperties{
60+
IPAddress: &containerinstance.IPAddress{
61+
Ports: &[]containerinstance.Port{{
62+
Port: to.Int32Ptr(80),
63+
}},
64+
IP: to.StringPtr("42.42.42.42"),
65+
},
66+
},
67+
}
68+
myContainer := containerinstance.Container{
69+
Name: to.StringPtr("myContainerID"),
70+
ContainerProperties: &containerinstance.ContainerProperties{
71+
Image: to.StringPtr("sha256:666"),
72+
Command: to.StringSlicePtr([]string{"mycommand"}),
73+
Ports: &[]containerinstance.ContainerPort{{
74+
Port: to.Int32Ptr(80),
75+
}},
76+
EnvironmentVariables: nil,
77+
InstanceView: &containerinstance.ContainerPropertiesInstanceView{
78+
RestartCount: nil,
79+
CurrentState: &containerinstance.ContainerState{
80+
State: to.StringPtr("Running"),
81+
},
82+
},
83+
Resources: &containerinstance.ResourceRequirements{
84+
Limits: &containerinstance.ResourceLimits{
85+
MemoryInGB: to.Float64Ptr(9),
86+
},
87+
},
88+
},
4889
}
4990

50-
suite.ctx = ctx
51-
suite.project = project
91+
var expectedContainer = containers.Container{
92+
ID: "myContainerID",
93+
Status: "Running",
94+
Image: "sha256:666",
95+
Command: "mycommand",
96+
MemoryLimit: 9,
97+
Ports: []containers.Port{{
98+
HostPort: uint32(80),
99+
ContainerPort: uint32(80),
100+
Protocol: "tcp",
101+
HostIP: "42.42.42.42",
102+
}},
103+
}
104+
105+
container, err := ContainerGroupToContainer("myContainerID", myContainerGroup, myContainer)
106+
Expect(err).To(BeNil())
107+
Expect(container).To(Equal(expectedContainer))
52108
}
53109

54-
func (suite *ConvertTestSuite) TestProjectName() {
55-
containerGroup, err := ToContainerGroup(suite.ctx, suite.project)
56-
require.NoError(suite.T(), err)
57-
require.Equal(suite.T(), *containerGroup.Name, expectedProjectName)
110+
func (suite *ConvertTestSuite) TestComposeContainerGroupToContainerWithDnsSideCarSide() {
111+
project := compose.Project{
112+
Name: "",
113+
Config: types.Config{
114+
Services: []types.ServiceConfig{
115+
{
116+
Name: "service1",
117+
Image: "image1",
118+
},
119+
{
120+
Name: "service2",
121+
Image: "image2",
122+
},
123+
},
124+
},
125+
}
126+
127+
group, err := ToContainerGroup(suite.ctx, project)
128+
Expect(err).To(BeNil())
129+
Expect(len(*group.Containers)).To(Equal(3))
130+
131+
Expect(*(*group.Containers)[0].Name).To(Equal("service1"))
132+
Expect(*(*group.Containers)[1].Name).To(Equal("service2"))
133+
Expect(*(*group.Containers)[2].Name).To(Equal(ComposeDNSSidecarName))
134+
135+
Expect(*(*group.Containers)[2].Command).To(Equal([]string{"sh", "-c", "echo 127.0.0.1 service1 >> /etc/hosts;echo 127.0.0.1 service2 >> /etc/hosts;sleep infinity"}))
136+
137+
Expect(*(*group.Containers)[0].Image).To(Equal("image1"))
138+
Expect(*(*group.Containers)[1].Image).To(Equal("image2"))
139+
Expect(*(*group.Containers)[2].Image).To(Equal(dnsSidecarImage))
140+
}
141+
142+
func (suite *ConvertTestSuite) TestComposeSingleContainerGroupToContainerNoDnsSideCarSide() {
143+
project := compose.Project{
144+
Name: "",
145+
Config: types.Config{
146+
Services: []types.ServiceConfig{
147+
{
148+
Name: "service1",
149+
Image: "image1",
150+
},
151+
},
152+
},
153+
}
154+
155+
group, err := ToContainerGroup(suite.ctx, project)
156+
Expect(err).To(BeNil())
157+
158+
Expect(len(*group.Containers)).To(Equal(1))
159+
Expect(*(*group.Containers)[0].Name).To(Equal("service1"))
160+
Expect(*(*group.Containers)[0].Image).To(Equal("image1"))
58161
}
59162

60163
func TestConvertTestSuite(t *testing.T) {
164+
RegisterTestingT(t)
61165
suite.Run(t, new(ConvertTestSuite))
62166
}

0 commit comments

Comments
 (0)