Fix Docker API compatibility with network alias (#17167)

* Add BaseHostsFile to container configuration
* Do not copy /etc/hosts file from host when creating a container using Docker API

Signed-off-by: Gavin Lam <gavin.oss@tutamail.com>
This commit is contained in:
Gavin Lam
2023-12-11 23:25:51 -05:00
parent 077b000996
commit db68764d8b
13 changed files with 93 additions and 2 deletions

View File

@ -291,6 +291,12 @@ type ContainerNetworkConfig struct {
// bind-mounted inside the container.
// Conflicts with HostAdd.
UseImageHosts bool
// BaseHostsFile is the path to a hosts file, the entries from this file
// are added to the containers hosts file. As special value "image" is
// allowed which uses the /etc/hosts file from within the image and "none"
// which uses no base file at all. If it is empty we should default
// to the base_hosts_file configuration in containers.conf.
BaseHostsFile string `json:"baseHostsFile,omitempty"`
// Hosts to add in container
// Will be appended to host's host file
HostAdd []string `json:"hostsAdd,omitempty"`

View File

@ -2267,7 +2267,14 @@ func (c *Container) addHosts() error {
if err != nil {
return fmt.Errorf("failed to get container ip host entries: %w", err)
}
baseHostFile, err := etchosts.GetBaseHostFile(c.runtime.config.Containers.BaseHostsFile, c.state.Mountpoint)
// Consider container level BaseHostsFile configuration first.
// If it is empty, fallback to containers.conf level configuration.
baseHostsFileConf := c.config.BaseHostsFile
if baseHostsFileConf == "" {
baseHostsFileConf = c.runtime.config.Containers.BaseHostsFile
}
baseHostFile, err := etchosts.GetBaseHostFile(baseHostsFileConf, c.state.Mountpoint)
if err != nil {
return err
}

View File

@ -2373,6 +2373,19 @@ func WithGroupEntry(groupEntry string) CtrCreateOption {
}
}
// WithBaseHostsFile sets the option to copy /etc/hosts file.
func WithBaseHostsFile(baseHostsFile string) CtrCreateOption {
return func(ctr *Container) error {
if ctr.valid {
return define.ErrCtrFinalized
}
ctr.config.BaseHostsFile = baseHostsFile
return nil
}
}
// WithMountAllDevices sets the option to mount all of a privileged container's
// host devices
func WithMountAllDevices() CtrCreateOption {

View File

@ -116,6 +116,8 @@ func CreateContainer(w http.ResponseWriter, r *http.Request) {
}
// moby always create the working directory
sg.CreateWorkingDir = true
// moby doesn't inherit /etc/hosts from host
sg.BaseHostsFile = "none"
ic := abi.ContainerEngine{Libpod: runtime}
report, err := ic.ContainerCreate(r.Context(), sg)

View File

@ -378,6 +378,9 @@ func createContainerOptions(rt *libpod.Runtime, s *specgen.SpecGenerator, pod *l
if s.GroupEntry != "" {
options = append(options, libpod.WithGroupEntry(s.GroupEntry))
}
if s.BaseHostsFile != "" {
options = append(options, libpod.WithBaseHostsFile(s.BaseHostsFile))
}
if s.Privileged {
options = append(options, libpod.WithMountAllDevices())

View File

@ -507,6 +507,13 @@ type ContainerNetworkConfig struct {
// specgen is stable so we can not change this right now.
// TODO (5.0): change to pointer
UseImageHosts bool `json:"use_image_hosts"`
// BaseHostsFile is the path to a hosts file, the entries from this file
// are added to the containers hosts file. As special value "image" is
// allowed which uses the /etc/hosts file from within the image and "none"
// which uses no base file at all. If it is empty we should default
// to the base_hosts_file configuration in containers.conf.
// Optional.
BaseHostsFile string `json:"base_hosts_file,omitempty"`
// HostAdd is a set of hosts which will be added to the container's
// /etc/hosts file.
// Conflicts with UseImageHosts.

View File

@ -0,0 +1,10 @@
etc hosts
===========
This test mounts a /etc/hosts file in the host containing an entry `foobar`, then create a container with an alias of the same hostname.
Validation
------------
* No /etc/hosts entries are copied from the host. There should be only one entry of the hostname, which is IP address of the alias.
* The hostname is resolved to IP address of the alias.

View File

@ -0,0 +1,19 @@
version: '3.3'
services:
test:
image: alpine
command: ["top"]
hostname: foobar
networks:
net1:
aliases:
- foobar
networks:
net1:
driver: bridge
ipam:
driver: default
config:
- subnet: 10.123.0.0/24

View File

@ -0,0 +1,2 @@
127.0.0.1 localhost
127.0.0.1 foobar

View File

@ -0,0 +1,5 @@
if ! is_rootless; then
mount --bind $TEST_ROOTDIR/etc_hosts/hosts /etc/hosts
else
$PODMAN_BIN unshare mount --bind $TEST_ROOTDIR/etc_hosts/hosts /etc/hosts
fi

View File

@ -0,0 +1,5 @@
if ! is_rootless; then
umount /etc/hosts
else
$PODMAN_BIN unshare umount /etc/hosts
fi

View File

@ -0,0 +1,12 @@
# -*- bash -*-
ctr_name="etc_hosts_test_1"
if [ "$TEST_FLAVOR" = "compose_v2" ]; then
ctr_name="etc_hosts-test-1"
fi
podman exec "$ctr_name" sh -c 'grep "foobar" /etc/hosts'
like "$output" "10\.123\.0\." "$testname : no entries are copied from the host"
podman exec "$ctr_name" sh -c 'getent hosts foobar | awk "{print \$1}"'
like "$output" "10\.123\.0\." "$testname : hostname is resolved to IP address of the alias"