diff options
-rw-r--r-- | cmd/podman/common.go | 4 | ||||
-rw-r--r-- | cmd/podman/shared/create.go | 5 | ||||
-rw-r--r-- | completions/bash/podman | 1 | ||||
-rw-r--r-- | docs/podman-create.1.md | 10 | ||||
-rw-r--r-- | docs/podman-run.1.md | 10 | ||||
-rw-r--r-- | libpod/container.go | 8 | ||||
-rw-r--r-- | libpod/container_internal_linux.go | 85 | ||||
-rw-r--r-- | libpod/options.go | 52 | ||||
-rw-r--r-- | pkg/spec/createconfig.go | 12 | ||||
-rw-r--r-- | test/e2e/run_test.go | 10 |
10 files changed, 157 insertions, 40 deletions
diff --git a/cmd/podman/common.go b/cmd/podman/common.go index 771738302..167b3e845 100644 --- a/cmd/podman/common.go +++ b/cmd/podman/common.go @@ -389,6 +389,10 @@ func getCreateFlags(c *cliconfig.PodmanCommand) { "Connect a container to a network", ) createFlags.Bool( + "no-hosts", false, + "Do not create /etc/hosts within the container, instead use the version from the image", + ) + createFlags.Bool( "oom-kill-disable", false, "Disable OOM Killer", ) diff --git a/cmd/podman/shared/create.go b/cmd/podman/shared/create.go index 5ce0b8865..5f7263cb6 100644 --- a/cmd/podman/shared/create.go +++ b/cmd/podman/shared/create.go @@ -357,6 +357,10 @@ func ParseCreateOpts(ctx context.Context, c *cliconfig.PodmanCommand, runtime *l return nil, errors.Errorf("--cpu-quota and --cpus cannot be set together") } + if c.Bool("no-hosts") && c.Flag("add-host").Changed { + return nil, errors.Errorf("--no-hosts and --add-host cannot be set together") + } + // EXPOSED PORTS var portBindings map[nat.Port][]nat.PortBinding if data != nil { @@ -646,6 +650,7 @@ func ParseCreateOpts(ctx context.Context, c *cliconfig.PodmanCommand, runtime *l GroupAdd: c.StringSlice("group-add"), Hostname: c.String("hostname"), HostAdd: c.StringSlice("add-host"), + NoHosts: c.Bool("no-hosts"), IDMappings: idmappings, Image: imageName, ImageID: imageID, diff --git a/completions/bash/podman b/completions/bash/podman index dfa673481..798d49ceb 100644 --- a/completions/bash/podman +++ b/completions/bash/podman @@ -1727,6 +1727,7 @@ _podman_container_run() { --memory-reservation --name --network + --no-hosts --oom-score-adj --pid --pids-limit diff --git a/docs/podman-create.1.md b/docs/podman-create.1.md index 2e176db76..f61deebd2 100644 --- a/docs/podman-create.1.md +++ b/docs/podman-create.1.md @@ -204,6 +204,9 @@ configuration passed to the container. Typically this is necessary when the host DNS configuration is invalid for the container (e.g., 127.0.0.1). When this is the case the **--dns** flags is necessary for every run. +The special value **none** can be specified to disable creation of **/etc/resolv.conf** in the container by Podman. +The **/etc/resolv.conf** file in the image will be used without changes. + **--dns-option**=[] Set custom DNS options @@ -457,6 +460,13 @@ Set the Network mode for the container Not implemented +**--no-hosts**=*true*|*false* + +Do not create /etc/hosts for the container. +By default, Podman will manage /etc/hosts, adding the container's own IP address and any hosts from **--add-host**. +**--no-hosts** disables this, and the image's **/etc/host** will be preserved unmodified. +This option conflicts with **--add-host**. + **--oom-kill-disable**=*true*|*false* Whether to disable OOM Killer for the container or not. diff --git a/docs/podman-run.1.md b/docs/podman-run.1.md index b8b3d51f0..5a311980f 100644 --- a/docs/podman-run.1.md +++ b/docs/podman-run.1.md @@ -210,6 +210,9 @@ configuration passed to the container. Typically this is necessary when the host DNS configuration is invalid for the container (e.g., 127.0.0.1). When this is the case the **--dns** flags is necessary for every run. +The special value **none** can be specified to disable creation of **/etc/resolv.conf** in the container by Podman. +The **/etc/resolv.conf** file in the image will be used without changes. + **--dns-option**=[] Set custom DNS options @@ -441,6 +444,13 @@ Set the Network mode for the container: Not implemented +**--no-hosts**=*true*|*false* + +Do not create /etc/hosts for the container. +By default, Podman will manage /etc/hosts, adding the container's own IP address and any hosts from **--add-host**. +**--no-hosts** disables this, and the image's **/etc/host** will be preserved unmodified. +This option conflicts with **--add-host**. + **--oom-kill-disable**=*true*|*false* Whether to disable OOM Killer for the container or not. diff --git a/libpod/container.go b/libpod/container.go index ec4e31026..806e75c63 100644 --- a/libpod/container.go +++ b/libpod/container.go @@ -293,6 +293,10 @@ type ContainerConfig struct { // namespace // These are not used unless CreateNetNS is true PortMappings []ocicni.PortMapping `json:"portMappings,omitempty"` + // UseImageResolvConf indicates that resolv.conf should not be + // bind-mounted inside the container. + // Conflicts with DNSServer, DNSSearch, DNSOption. + UseImageResolvConf bool // DNS servers to use in container resolv.conf // Will override servers in host resolv if set DNSServer []net.IP `json:"dnsServer,omitempty"` @@ -302,6 +306,10 @@ type ContainerConfig struct { // DNS options to be set in container resolv.conf // With override options in host resolv if set DNSOption []string `json:"dnsOption,omitempty"` + // UseImageHosts indicates that /etc/hosts should not be + // bind-mounted inside the container. + // Conflicts with HostAdd. + UseImageHosts bool // Hosts to add in container // Will be appended to host's host file HostAdd []string `json:"hostsAdd,omitempty"` diff --git a/libpod/container_internal_linux.go b/libpod/container_internal_linux.go index c6c9ceb0c..02f8d6aa4 100644 --- a/libpod/container_internal_linux.go +++ b/libpod/container_internal_linux.go @@ -703,10 +703,11 @@ func (c *Container) makeBindMounts() error { } } - if c.config.NetNsCtr != "" { - // We share a net namespace + if c.config.NetNsCtr != "" && (!c.config.UseImageResolvConf || !c.config.UseImageHosts) { + // We share a net namespace. // We want /etc/resolv.conf and /etc/hosts from the - // other container + // other container. Unless we're not creating both of + // them. depCtr, err := c.runtime.state.Container(c.config.NetNsCtr) if err != nil { return errors.Wrapf(err, "error fetching dependency %s of container %s", c.config.NetNsCtr, c.ID()) @@ -718,53 +719,65 @@ func (c *Container) makeBindMounts() error { return errors.Wrapf(err, "error fetching bind mounts from dependency %s of container %s", depCtr.ID(), c.ID()) } - // The other container may not have a resolv.conf or /etc/hosts - // If it doesn't, don't copy them - resolvPath, exists := bindMounts["/etc/resolv.conf"] - if exists { - c.state.BindMounts["/etc/resolv.conf"] = resolvPath + if !c.config.UseImageResolvConf { + // The other container may not have a resolv.conf or /etc/hosts + // If it doesn't, don't copy them + resolvPath, exists := bindMounts["/etc/resolv.conf"] + if exists { + c.state.BindMounts["/etc/resolv.conf"] = resolvPath + } } - // check if dependency container has an /etc/hosts file - hostsPath, exists := bindMounts["/etc/hosts"] - if !exists { - return errors.Errorf("error finding hosts file of dependency container %s for container %s", depCtr.ID(), c.ID()) - } + if !c.config.UseImageHosts { + // check if dependency container has an /etc/hosts file + hostsPath, exists := bindMounts["/etc/hosts"] + if !exists { + return errors.Errorf("error finding hosts file of dependency container %s for container %s", depCtr.ID(), c.ID()) + } - depCtr.lock.Lock() - // generate a hosts file for the dependency container, - // based on either its old hosts file, or the default, - // and add the relevant information from the new container (hosts and IP) - hostsPath, err = depCtr.appendHosts(hostsPath, c) + depCtr.lock.Lock() + // generate a hosts file for the dependency container, + // based on either its old hosts file, or the default, + // and add the relevant information from the new container (hosts and IP) + hostsPath, err = depCtr.appendHosts(hostsPath, c) - if err != nil { + if err != nil { + depCtr.lock.Unlock() + return errors.Wrapf(err, "error creating hosts file for container %s which depends on container %s", c.ID(), depCtr.ID()) + } depCtr.lock.Unlock() - return errors.Wrapf(err, "error creating hosts file for container %s which depends on container %s", c.ID(), depCtr.ID()) - } - depCtr.lock.Unlock() - // finally, save it in the new container - c.state.BindMounts["/etc/hosts"] = hostsPath + // finally, save it in the new container + c.state.BindMounts["/etc/hosts"] = hostsPath + } } else { - newResolv, err := c.generateResolvConf() - if err != nil { - return errors.Wrapf(err, "error creating resolv.conf for container %s", c.ID()) + if !c.config.UseImageResolvConf { + newResolv, err := c.generateResolvConf() + if err != nil { + return errors.Wrapf(err, "error creating resolv.conf for container %s", c.ID()) + } + c.state.BindMounts["/etc/resolv.conf"] = newResolv } - c.state.BindMounts["/etc/resolv.conf"] = newResolv - newHosts, err := c.generateHosts("/etc/hosts") - if err != nil { - return errors.Wrapf(err, "error creating hosts file for container %s", c.ID()) + if !c.config.UseImageHosts { + newHosts, err := c.generateHosts("/etc/hosts") + if err != nil { + return errors.Wrapf(err, "error creating hosts file for container %s", c.ID()) + } + c.state.BindMounts["/etc/hosts"] = newHosts } - c.state.BindMounts["/etc/hosts"] = newHosts } - if err := label.Relabel(c.state.BindMounts["/etc/hosts"], c.config.MountLabel, true); err != nil { - return err + if c.state.BindMounts["/etc/hosts"] != "" { + if err := label.Relabel(c.state.BindMounts["/etc/hosts"], c.config.MountLabel, true); err != nil { + return err + } } - if err := label.Relabel(c.state.BindMounts["/etc/resolv.conf"], c.config.MountLabel, true); err != nil { - return err + if c.state.BindMounts["/etc/resolv.conf"] != "" { + if err := label.Relabel(c.state.BindMounts["/etc/resolv.conf"], c.config.MountLabel, true); err != nil { + return err + } } } diff --git a/libpod/options.go b/libpod/options.go index 1bf3ff9e6..3ca80e96c 100644 --- a/libpod/options.go +++ b/libpod/options.go @@ -997,6 +997,9 @@ func WithDNSSearch(searchDomains []string) CtrCreateOption { if ctr.valid { return ErrCtrFinalized } + if ctr.config.UseImageResolvConf { + return errors.Wrapf(ErrInvalidArg, "cannot add DNS search domains if container will not create /etc/resolv.conf") + } ctr.config.DNSSearch = searchDomains return nil } @@ -1008,6 +1011,9 @@ func WithDNS(dnsServers []string) CtrCreateOption { if ctr.valid { return ErrCtrFinalized } + if ctr.config.UseImageResolvConf { + return errors.Wrapf(ErrInvalidArg, "cannot add DNS servers if container will not create /etc/resolv.conf") + } var dns []net.IP for _, i := range dnsServers { result := net.ParseIP(i) @@ -1027,6 +1033,9 @@ func WithDNSOption(dnsOptions []string) CtrCreateOption { if ctr.valid { return ErrCtrFinalized } + if ctr.config.UseImageResolvConf { + return errors.Wrapf(ErrInvalidArg, "cannot add DNS options if container will not create /etc/resolv.conf") + } ctr.config.DNSOption = dnsOptions return nil } @@ -1038,6 +1047,11 @@ func WithHosts(hosts []string) CtrCreateOption { if ctr.valid { return ErrCtrFinalized } + + if ctr.config.UseImageHosts { + return errors.Wrapf(ErrInvalidArg, "cannot add hosts if container will not create /etc/hosts") + } + ctr.config.HostAdd = hosts return nil } @@ -1184,6 +1198,44 @@ func WithCtrNamespace(ns string) CtrCreateOption { } } +// WithUseImageResolvConf tells the container not to bind-mount resolv.conf in. +// This conflicts with other DNS-related options. +func WithUseImageResolvConf() CtrCreateOption { + return func(ctr *Container) error { + if ctr.valid { + return ErrCtrFinalized + } + + if len(ctr.config.DNSServer) != 0 || + len(ctr.config.DNSSearch) != 0 || + len(ctr.config.DNSOption) != 0 { + return errors.Wrapf(ErrInvalidArg, "not creating resolv.conf conflicts with DNS options") + } + + ctr.config.UseImageResolvConf = true + + return nil + } +} + +// WithUseImageHosts tells the container not to bind-mount /etc/hosts in. +// This conflicts with WithHosts(). +func WithUseImageHosts() CtrCreateOption { + return func(ctr *Container) error { + if ctr.valid { + return ErrCtrFinalized + } + + if len(ctr.config.HostAdd) != 0 { + return errors.Wrapf(ErrInvalidArg, "not creating /etc/hosts conflicts with adding to the hosts file") + } + + ctr.config.UseImageHosts = true + + return nil + } +} + // withIsInfra sets the container to be an infra container. This means the container will be sometimes hidden // and expected to be the first container in the pod. func withIsInfra() CtrCreateOption { diff --git a/pkg/spec/createconfig.go b/pkg/spec/createconfig.go index 118fbad72..79a318771 100644 --- a/pkg/spec/createconfig.go +++ b/pkg/spec/createconfig.go @@ -88,6 +88,7 @@ type CreateConfig struct { ExposedPorts map[nat.Port]struct{} GroupAdd []string // group-add HealthCheck *manifest.Schema2HealthConfig + NoHosts bool HostAdd []string //add-host Hostname string //hostname Image string @@ -505,12 +506,19 @@ func (c *CreateConfig) GetContainerCreateOptions(runtime *libpod.Runtime, pod *l options = append(options, libpod.WithDNSSearch(c.DNSSearch)) } if len(c.DNSServers) > 0 { - options = append(options, libpod.WithDNS(c.DNSServers)) + if len(c.DNSServers) == 1 && strings.ToLower(c.DNSServers[0]) == "none" { + options = append(options, libpod.WithUseImageResolvConf()) + } else { + options = append(options, libpod.WithDNS(c.DNSServers)) + } } if len(c.DNSOpt) > 0 { options = append(options, libpod.WithDNSOption(c.DNSOpt)) } - if len(c.HostAdd) > 0 { + if c.NoHosts { + options = append(options, libpod.WithUseImageHosts()) + } + if len(c.HostAdd) > 0 && !c.NoHosts { options = append(options, libpod.WithHosts(c.HostAdd)) } logPath := getLoggingPath(c.LogDriverOpt) diff --git a/test/e2e/run_test.go b/test/e2e/run_test.go index b0dc66707..2daf2fe5b 100644 --- a/test/e2e/run_test.go +++ b/test/e2e/run_test.go @@ -749,13 +749,19 @@ USER mail` It("podman run with bad healthcheck timeout", func() { session := podmanTest.Podman([]string{"run", "-dt", "--healthcheck-cmd", "foo", "--healthcheck-timeout", "0s", ALPINE, "top"}) - session.Wait() + session.WaitWithDefaultTimeout() Expect(session.ExitCode()).ToNot(Equal(0)) }) It("podman run with bad healthcheck start-period", func() { session := podmanTest.Podman([]string{"run", "-dt", "--healthcheck-cmd", "foo", "--healthcheck-start-period", "-1s", ALPINE, "top"}) - session.Wait() + session.WaitWithDefaultTimeout() + Expect(session.ExitCode()).ToNot(Equal(0)) + }) + + It("podman run with --add-host and --no-hosts fails", func() { + session := podmanTest.Podman([]string{"run", "-dt", "--add-host", "test1:127.0.0.1", "--no-hosts", ALPINE, "top"}) + session.WaitWithDefaultTimeout() Expect(session.ExitCode()).ToNot(Equal(0)) }) }) |