minimalist container image to setup /etc/hosts on ACI

Signed-off-by: Nicolas De Loof <nicolas.deloof@gmail.com>
This commit is contained in:
Nicolas De Loof 2020-10-16 14:29:36 +02:00
parent 455c08c245
commit 553865f294
No known key found for this signature in database
GPG Key ID: 9858809D6F8F6E7E
9 changed files with 161 additions and 14 deletions

View File

@ -42,7 +42,7 @@ const (
// ComposeDNSSidecarName name of the dns sidecar container
ComposeDNSSidecarName = "aci--dns--sidecar"
dnsSidecarImage = "busybox:1.31.1"
dnsSidecarImage = "docker/aci-hostnames-sidecar"
)
// ToContainerGroup converts a compose project into a ACI container group
@ -129,19 +129,15 @@ func ToContainerGroup(ctx context.Context, aciContext store.AciContext, p types.
}
func getDNSSidecar(containers []containerinstance.Container) containerinstance.Container {
var commands []string
var names []string
for _, container := range containers {
commands = append(commands, fmt.Sprintf("echo 127.0.0.1 %s >> /etc/hosts", *container.Name))
names = append(names, *container.Name)
}
// ACI restart policy is currently at container group level, cannot let the sidecar terminate quietly once /etc/hosts has been edited
// Pricing is done at the container group level so letting the sidecar container "sleep" should not impact the price for the whole group
commands = append(commands, "sleep infinity")
alpineCmd := []string{"sh", "-c", strings.Join(commands, ";")}
dnsSideCar := containerinstance.Container{
Name: to.StringPtr(ComposeDNSSidecarName),
ContainerProperties: &containerinstance.ContainerProperties{
Image: to.StringPtr(dnsSidecarImage),
Command: &alpineCmd,
Command: &names,
Resources: &containerinstance.ResourceRequirements{
Requests: &containerinstance.ResourceRequests{
MemoryInGB: to.Float64Ptr(0.1),

View File

@ -179,7 +179,7 @@ func TestComposeContainerGroupToContainerWithDnsSideCarSide(t *testing.T) {
assert.Equal(t, *(*group.Containers)[1].Name, "service2")
assert.Equal(t, *(*group.Containers)[2].Name, ComposeDNSSidecarName)
assert.DeepEqual(t, *(*group.Containers)[2].Command, []string{"sh", "-c", "echo 127.0.0.1 service1 >> /etc/hosts;echo 127.0.0.1 service2 >> /etc/hosts;sleep infinity"})
assert.DeepEqual(t, *(*group.Containers)[2].Command, []string{"service1", "service2"})
assert.Equal(t, *(*group.Containers)[0].Image, "image1")
assert.Equal(t, *(*group.Containers)[1].Image, "image2")

22
aci/etchosts/Dockerfile Normal file
View File

@ -0,0 +1,22 @@
# Copyright 2020 Docker Compose CLI authors
# Licensed under the Apache License, Version 2.0 (the "License");
# you may not use this file except in compliance with the License.
# You may obtain a copy of the License at
# http://www.apache.org/licenses/LICENSE-2.0
# Unless required by applicable law or agreed to in writing, software
# distributed under the License is distributed on an "AS IS" BASIS,
# WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
# See the License for the specific language governing permissions and
# limitations under the License.
FROM golang:1.15 AS builder
WORKDIR $GOPATH/src/github.com/docker/compose-cli/aci/etchosts
COPY . .
RUN CGO_ENABLED=0 go build -ldflags="-w -s" -o /go/bin/hosts main/main.go
FROM scratch
COPY --from=builder /go/bin/hosts /hosts
ENTRYPOINT ["/hosts"]

35
aci/etchosts/hosts.go Normal file
View File

@ -0,0 +1,35 @@
/*
Copyright 2020 Docker Compose CLI authors
Licensed under the Apache License, Version 2.0 (the "License");
you may not use this file except in compliance with the License.
You may obtain a copy of the License at
http://www.apache.org/licenses/LICENSE-2.0
Unless required by applicable law or agreed to in writing, software
distributed under the License is distributed on an "AS IS" BASIS,
WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
See the License for the specific language governing permissions and
limitations under the License.
*/
package etchosts
import (
"os"
)
// SetHostNames appends hosts aliases for loopback address to etc/host file
func SetHostNames(file string, hosts ...string) error {
f, err := os.OpenFile(file, os.O_APPEND|os.O_CREATE|os.O_WRONLY, 0644)
if err != nil {
return err
}
defer f.Close() //nolint:errcheck
for _, host := range hosts {
_, err = f.WriteString("\n127.0.0.1 " + host)
}
return err
}

View File

@ -0,0 +1,48 @@
/*
Copyright 2020 Docker Compose CLI authors
Licensed under the Apache License, Version 2.0 (the "License");
you may not use this file except in compliance with the License.
You may obtain a copy of the License at
http://www.apache.org/licenses/LICENSE-2.0
Unless required by applicable law or agreed to in writing, software
distributed under the License is distributed on an "AS IS" BASIS,
WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
See the License for the specific language governing permissions and
limitations under the License.
*/
package etchosts
import (
"io/ioutil"
"os"
"path/filepath"
"testing"
"gotest.tools/v3/assert"
"gotest.tools/v3/fs"
"gotest.tools/v3/golden"
)
func TestSetDomain(t *testing.T) {
dir := fs.NewDir(t, "resolv").Path()
f := filepath.Join(dir, "hosts")
touch(t, f)
err := SetHostNames(f, "foo", "bar", "zot")
assert.NilError(t, err)
got, err := ioutil.ReadFile(f)
assert.NilError(t, err)
golden.Assert(t, string(got), "etchosts.golden")
}
func touch(t *testing.T, f string) {
file, err := os.Create(f)
assert.NilError(t, err)
err = file.Close()
assert.NilError(t, err)
}

43
aci/etchosts/main/main.go Normal file
View File

@ -0,0 +1,43 @@
/*
Copyright 2020 Docker Compose CLI authors
Licensed under the Apache License, Version 2.0 (the "License");
you may not use this file except in compliance with the License.
You may obtain a copy of the License at
http://www.apache.org/licenses/LICENSE-2.0
Unless required by applicable law or agreed to in writing, software
distributed under the License is distributed on an "AS IS" BASIS,
WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
See the License for the specific language governing permissions and
limitations under the License.
*/
package main
import (
"fmt"
"os"
"github.com/docker/compose-cli/aci/etchosts"
)
const hosts = "/etc/hosts"
func main() {
if len(os.Args) < 2 {
fmt.Fprint(os.Stderr, "usage: hosts HOSTNAME [HOSTNAME]")
os.Exit(1)
}
err := etchosts.SetHostNames(hosts, os.Args[1:]...)
if err != nil {
fmt.Fprint(os.Stderr, err.Error())
os.Exit(1)
}
// ACI restart policy is currently at container group level, cannot let the sidecar terminate quietly once /etc/hosts has been edited
// Pricing is done at the container group level so letting the sidecar container "sleep" should not impact the price for the whole group
fmt.Scanln() // pause
}

4
aci/etchosts/testdata/etchosts.golden vendored Normal file
View File

@ -0,0 +1,4 @@
127.0.0.1 foo
127.0.0.1 bar
127.0.0.1 zot

View File

@ -12,11 +12,10 @@
# See the License for the specific language governing permissions and
# limitations under the License.
FROM golang:1.14.4-alpine AS builder
FROM FROM golang:1.15 AS builder
WORKDIR $GOPATH/src/github.com/docker/compose-cli/ecs/resolv
COPY . .
RUN GOOS=linux GOARCH=amd64 go build -ldflags="-w -s" -o /go/bin/resolv main/main.go
RUN chmod +x /go/bin/resolv
RUN CGO_ENABLED=0 go build -ldflags="-w -s" -o /go/bin/resolv main/main.go
FROM scratch
COPY --from=builder /go/bin/resolv /resolv

View File

@ -12,10 +12,10 @@
# See the License for the specific language governing permissions and
# limitations under the License.
FROM golang:1.14.4-alpine AS builder
FROM FROM golang:1.15 AS builder
WORKDIR $GOPATH/src/github.com/docker/compose-cli/ecs/secrets
COPY . .
RUN GOOS=linux GOARCH=amd64 go build -ldflags="-w -s" -o /go/bin/secrets main/main.go
RUN CGO_ENABLED=0 go build -ldflags="-w -s" -o /go/bin/secrets main/main.go
FROM scratch
COPY --from=builder /go/bin/secrets /secrets