mirror of
https://github.com/containers/podman.git
synced 2025-06-24 19:42:56 +08:00
Merge pull request #11314 from Luap99/expose-ports
podman inspect show exposed ports
This commit is contained in:
@ -99,6 +99,11 @@ func (c *Container) Commit(ctx context.Context, destImage string, options Contai
|
|||||||
for _, p := range c.config.PortMappings {
|
for _, p := range c.config.PortMappings {
|
||||||
importBuilder.SetPort(fmt.Sprintf("%d/%s", p.ContainerPort, p.Protocol))
|
importBuilder.SetPort(fmt.Sprintf("%d/%s", p.ContainerPort, p.Protocol))
|
||||||
}
|
}
|
||||||
|
for port, protocols := range c.config.ExposedPorts {
|
||||||
|
for _, protocol := range protocols {
|
||||||
|
importBuilder.SetPort(fmt.Sprintf("%d/%s", port, protocol))
|
||||||
|
}
|
||||||
|
}
|
||||||
// Labels
|
// Labels
|
||||||
for k, v := range c.Labels() {
|
for k, v := range c.Labels() {
|
||||||
importBuilder.SetLabel(k, v)
|
importBuilder.SetLabel(k, v)
|
||||||
|
@ -229,6 +229,12 @@ type ContainerNetworkConfig struct {
|
|||||||
// namespace
|
// namespace
|
||||||
// These are not used unless CreateNetNS is true
|
// These are not used unless CreateNetNS is true
|
||||||
PortMappings []ocicni.PortMapping `json:"portMappings,omitempty"`
|
PortMappings []ocicni.PortMapping `json:"portMappings,omitempty"`
|
||||||
|
// ExposedPorts are the ports which are exposed but not forwarded
|
||||||
|
// into the container.
|
||||||
|
// The map key is the port and the string slice contains the protocols,
|
||||||
|
// e.g. tcp and udp
|
||||||
|
// These are only set when exposed ports are given but not published.
|
||||||
|
ExposedPorts map[uint16][]string `json:"exposedPorts,omitempty"`
|
||||||
// UseImageResolvConf indicates that resolv.conf should not be
|
// UseImageResolvConf indicates that resolv.conf should not be
|
||||||
// bind-mounted inside the container.
|
// bind-mounted inside the container.
|
||||||
// Conflicts with DNSServer, DNSSearch, DNSOption.
|
// Conflicts with DNSServer, DNSSearch, DNSOption.
|
||||||
|
@ -624,7 +624,7 @@ func (c *Container) generateInspectContainerHostConfig(ctrSpec *spec.Spec, named
|
|||||||
// Port bindings.
|
// Port bindings.
|
||||||
// Only populate if we're using CNI to configure the network.
|
// Only populate if we're using CNI to configure the network.
|
||||||
if c.config.CreateNetNS {
|
if c.config.CreateNetNS {
|
||||||
hostConfig.PortBindings = makeInspectPortBindings(c.config.PortMappings)
|
hostConfig.PortBindings = makeInspectPortBindings(c.config.PortMappings, c.config.ExposedPorts)
|
||||||
} else {
|
} else {
|
||||||
hostConfig.PortBindings = make(map[string][]define.InspectHostPort)
|
hostConfig.PortBindings = make(map[string][]define.InspectHostPort)
|
||||||
}
|
}
|
||||||
|
@ -1015,7 +1015,7 @@ func (c *Container) getContainerNetworkInfo() (*define.InspectNetworkSettings, e
|
|||||||
}
|
}
|
||||||
|
|
||||||
settings := new(define.InspectNetworkSettings)
|
settings := new(define.InspectNetworkSettings)
|
||||||
settings.Ports = makeInspectPortBindings(c.config.PortMappings)
|
settings.Ports = makeInspectPortBindings(c.config.PortMappings, c.config.ExposedPorts)
|
||||||
|
|
||||||
networks, isDefault, err := c.networks()
|
networks, isDefault, err := c.networks()
|
||||||
if err != nil {
|
if err != nil {
|
||||||
|
@ -1041,7 +1041,7 @@ func WithDependencyCtrs(ctrs []*Container) CtrCreateOption {
|
|||||||
// namespace with a minimal configuration.
|
// namespace with a minimal configuration.
|
||||||
// An optional array of port mappings can be provided.
|
// An optional array of port mappings can be provided.
|
||||||
// Conflicts with WithNetNSFrom().
|
// Conflicts with WithNetNSFrom().
|
||||||
func WithNetNS(portMappings []ocicni.PortMapping, postConfigureNetNS bool, netmode string, networks []string) CtrCreateOption {
|
func WithNetNS(portMappings []ocicni.PortMapping, exposedPorts map[uint16][]string, postConfigureNetNS bool, netmode string, networks []string) CtrCreateOption {
|
||||||
return func(ctr *Container) error {
|
return func(ctr *Container) error {
|
||||||
if ctr.valid {
|
if ctr.valid {
|
||||||
return define.ErrCtrFinalized
|
return define.ErrCtrFinalized
|
||||||
@ -1051,6 +1051,7 @@ func WithNetNS(portMappings []ocicni.PortMapping, postConfigureNetNS bool, netmo
|
|||||||
ctr.config.NetMode = namespaces.NetworkMode(netmode)
|
ctr.config.NetMode = namespaces.NetworkMode(netmode)
|
||||||
ctr.config.CreateNetNS = true
|
ctr.config.CreateNetNS = true
|
||||||
ctr.config.PortMappings = portMappings
|
ctr.config.PortMappings = portMappings
|
||||||
|
ctr.config.ExposedPorts = exposedPorts
|
||||||
|
|
||||||
ctr.config.Networks = networks
|
ctr.config.Networks = networks
|
||||||
|
|
||||||
|
@ -616,7 +616,7 @@ func (p *Pod) Inspect() (*define.InspectPodData, error) {
|
|||||||
infraConfig.Networks = append(infraConfig.Networks, p.config.InfraContainer.Networks...)
|
infraConfig.Networks = append(infraConfig.Networks, p.config.InfraContainer.Networks...)
|
||||||
}
|
}
|
||||||
infraConfig.NetworkOptions = p.config.InfraContainer.NetworkOptions
|
infraConfig.NetworkOptions = p.config.InfraContainer.NetworkOptions
|
||||||
infraConfig.PortBindings = makeInspectPortBindings(p.config.InfraContainer.PortBindings)
|
infraConfig.PortBindings = makeInspectPortBindings(p.config.InfraContainer.PortBindings, nil)
|
||||||
}
|
}
|
||||||
|
|
||||||
inspectData := define.InspectPodData{
|
inspectData := define.InspectPodData{
|
||||||
|
@ -112,7 +112,8 @@ func (r *Runtime) makeInfraContainer(ctx context.Context, p *Pod, imgName, rawIm
|
|||||||
options = append(options, WithNetworkOptions(p.config.InfraContainer.NetworkOptions))
|
options = append(options, WithNetworkOptions(p.config.InfraContainer.NetworkOptions))
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
options = append(options, WithNetNS(p.config.InfraContainer.PortBindings, !p.config.InfraContainer.Userns.IsHost(), netmode, p.config.InfraContainer.Networks))
|
// FIXME allow pods to have exposed ports
|
||||||
|
options = append(options, WithNetNS(p.config.InfraContainer.PortBindings, nil, !p.config.InfraContainer.Userns.IsHost(), netmode, p.config.InfraContainer.Networks))
|
||||||
}
|
}
|
||||||
|
|
||||||
// For each option in InfraContainerConfig - if set, pass into
|
// For each option in InfraContainerConfig - if set, pass into
|
||||||
|
@ -295,8 +295,8 @@ func writeHijackHeader(r *http.Request, conn io.Writer) {
|
|||||||
}
|
}
|
||||||
|
|
||||||
// Convert OCICNI port bindings into Inspect-formatted port bindings.
|
// Convert OCICNI port bindings into Inspect-formatted port bindings.
|
||||||
func makeInspectPortBindings(bindings []ocicni.PortMapping) map[string][]define.InspectHostPort {
|
func makeInspectPortBindings(bindings []ocicni.PortMapping, expose map[uint16][]string) map[string][]define.InspectHostPort {
|
||||||
portBindings := make(map[string][]define.InspectHostPort)
|
portBindings := make(map[string][]define.InspectHostPort, len(bindings))
|
||||||
for _, port := range bindings {
|
for _, port := range bindings {
|
||||||
key := fmt.Sprintf("%d/%s", port.ContainerPort, port.Protocol)
|
key := fmt.Sprintf("%d/%s", port.ContainerPort, port.Protocol)
|
||||||
hostPorts := portBindings[key]
|
hostPorts := portBindings[key]
|
||||||
@ -309,6 +309,15 @@ func makeInspectPortBindings(bindings []ocicni.PortMapping) map[string][]define.
|
|||||||
})
|
})
|
||||||
portBindings[key] = hostPorts
|
portBindings[key] = hostPorts
|
||||||
}
|
}
|
||||||
|
// add exposed ports without host port information to match docker
|
||||||
|
for port, protocols := range expose {
|
||||||
|
for _, protocol := range protocols {
|
||||||
|
key := fmt.Sprintf("%d/%s", port, protocol)
|
||||||
|
if _, ok := portBindings[key]; !ok {
|
||||||
|
portBindings[key] = nil
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
return portBindings
|
return portBindings
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -242,7 +242,7 @@ func namespaceOptions(ctx context.Context, s *specgen.SpecGenerator, rt *libpod.
|
|||||||
}
|
}
|
||||||
toReturn = append(toReturn, libpod.WithNetNSFrom(netCtr))
|
toReturn = append(toReturn, libpod.WithNetNSFrom(netCtr))
|
||||||
case specgen.Slirp:
|
case specgen.Slirp:
|
||||||
portMappings, err := createPortMappings(ctx, s, imageData)
|
portMappings, expose, err := createPortMappings(ctx, s, imageData)
|
||||||
if err != nil {
|
if err != nil {
|
||||||
return nil, err
|
return nil, err
|
||||||
}
|
}
|
||||||
@ -250,15 +250,15 @@ func namespaceOptions(ctx context.Context, s *specgen.SpecGenerator, rt *libpod.
|
|||||||
if s.NetNS.Value != "" {
|
if s.NetNS.Value != "" {
|
||||||
val = fmt.Sprintf("slirp4netns:%s", s.NetNS.Value)
|
val = fmt.Sprintf("slirp4netns:%s", s.NetNS.Value)
|
||||||
}
|
}
|
||||||
toReturn = append(toReturn, libpod.WithNetNS(portMappings, postConfigureNetNS, val, nil))
|
toReturn = append(toReturn, libpod.WithNetNS(portMappings, expose, postConfigureNetNS, val, nil))
|
||||||
case specgen.Private:
|
case specgen.Private:
|
||||||
fallthrough
|
fallthrough
|
||||||
case specgen.Bridge:
|
case specgen.Bridge:
|
||||||
portMappings, err := createPortMappings(ctx, s, imageData)
|
portMappings, expose, err := createPortMappings(ctx, s, imageData)
|
||||||
if err != nil {
|
if err != nil {
|
||||||
return nil, err
|
return nil, err
|
||||||
}
|
}
|
||||||
toReturn = append(toReturn, libpod.WithNetNS(portMappings, postConfigureNetNS, "bridge", s.CNINetworks))
|
toReturn = append(toReturn, libpod.WithNetNS(portMappings, expose, postConfigureNetNS, "bridge", s.CNINetworks))
|
||||||
}
|
}
|
||||||
|
|
||||||
if s.UseImageHosts {
|
if s.UseImageHosts {
|
||||||
|
@ -254,17 +254,15 @@ func ParsePortMapping(portMappings []types.PortMapping) ([]ocicni.PortMapping, m
|
|||||||
}
|
}
|
||||||
|
|
||||||
// Make final port mappings for the container
|
// Make final port mappings for the container
|
||||||
func createPortMappings(ctx context.Context, s *specgen.SpecGenerator, imageData *libimage.ImageData) ([]ocicni.PortMapping, error) {
|
func createPortMappings(ctx context.Context, s *specgen.SpecGenerator, imageData *libimage.ImageData) ([]ocicni.PortMapping, map[uint16][]string, error) {
|
||||||
finalMappings, containerPortValidate, hostPortValidate, err := ParsePortMapping(s.PortMappings)
|
finalMappings, containerPortValidate, hostPortValidate, err := ParsePortMapping(s.PortMappings)
|
||||||
if err != nil {
|
if err != nil {
|
||||||
return nil, err
|
return nil, nil, err
|
||||||
}
|
}
|
||||||
|
|
||||||
// If not publishing exposed ports, or if we are publishing and there is
|
// No exposed ports so return the port mappings we've made so far.
|
||||||
// nothing to publish - then just return the port mappings we've made so
|
if len(s.Expose) == 0 && imageData == nil {
|
||||||
// far.
|
return finalMappings, nil, nil
|
||||||
if !s.PublishExposedPorts || (len(s.Expose) == 0 && imageData == nil) {
|
|
||||||
return finalMappings, nil
|
|
||||||
}
|
}
|
||||||
|
|
||||||
logrus.Debugf("Adding exposed ports")
|
logrus.Debugf("Adding exposed ports")
|
||||||
@ -273,7 +271,7 @@ func createPortMappings(ctx context.Context, s *specgen.SpecGenerator, imageData
|
|||||||
if imageData != nil {
|
if imageData != nil {
|
||||||
expose, err = GenExposedPorts(imageData.Config.ExposedPorts)
|
expose, err = GenExposedPorts(imageData.Config.ExposedPorts)
|
||||||
if err != nil {
|
if err != nil {
|
||||||
return nil, err
|
return nil, nil, err
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
@ -289,11 +287,11 @@ func createPortMappings(ctx context.Context, s *specgen.SpecGenerator, imageData
|
|||||||
// Validate protocol first
|
// Validate protocol first
|
||||||
protocols, err := checkProtocol(proto, false)
|
protocols, err := checkProtocol(proto, false)
|
||||||
if err != nil {
|
if err != nil {
|
||||||
return nil, errors.Wrapf(err, "error validating protocols for exposed port %d", port)
|
return nil, nil, errors.Wrapf(err, "error validating protocols for exposed port %d", port)
|
||||||
}
|
}
|
||||||
|
|
||||||
if port == 0 {
|
if port == 0 {
|
||||||
return nil, errors.Errorf("cannot expose 0 as it is not a valid port number")
|
return nil, nil, errors.Errorf("cannot expose 0 as it is not a valid port number")
|
||||||
}
|
}
|
||||||
|
|
||||||
// Check to see if the port is already present in existing
|
// Check to see if the port is already present in existing
|
||||||
@ -317,6 +315,11 @@ func createPortMappings(ctx context.Context, s *specgen.SpecGenerator, imageData
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
// If not publishing exposed ports return mappings and exposed ports.
|
||||||
|
if !s.PublishExposedPorts {
|
||||||
|
return finalMappings, toExpose, nil
|
||||||
|
}
|
||||||
|
|
||||||
// We now have a final list of ports that we want exposed.
|
// We now have a final list of ports that we want exposed.
|
||||||
// Let's find empty, unallocated host ports for them.
|
// Let's find empty, unallocated host ports for them.
|
||||||
for port, protocols := range toExpose {
|
for port, protocols := range toExpose {
|
||||||
@ -332,7 +335,7 @@ func createPortMappings(ctx context.Context, s *specgen.SpecGenerator, imageData
|
|||||||
// unfortunate for the UDP case.
|
// unfortunate for the UDP case.
|
||||||
candidate, err := utils.GetRandomPort()
|
candidate, err := utils.GetRandomPort()
|
||||||
if err != nil {
|
if err != nil {
|
||||||
return nil, err
|
return nil, nil, err
|
||||||
}
|
}
|
||||||
|
|
||||||
// Check if the host port is already bound
|
// Check if the host port is already bound
|
||||||
@ -363,12 +366,12 @@ func createPortMappings(ctx context.Context, s *specgen.SpecGenerator, imageData
|
|||||||
}
|
}
|
||||||
if tries == 0 && hostPort == 0 {
|
if tries == 0 && hostPort == 0 {
|
||||||
// We failed to find an open port.
|
// We failed to find an open port.
|
||||||
return nil, errors.Errorf("failed to find an open port to expose container port %d on the host", port)
|
return nil, nil, errors.Errorf("failed to find an open port to expose container port %d on the host", port)
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
return finalMappings, nil
|
return finalMappings, nil, nil
|
||||||
}
|
}
|
||||||
|
|
||||||
// Check a string to ensure it is a comma-separated set of valid protocols
|
// Check a string to ensure it is a comma-separated set of valid protocols
|
||||||
|
@ -329,4 +329,40 @@ var _ = Describe("Podman commit", func() {
|
|||||||
session.WaitWithDefaultTimeout()
|
session.WaitWithDefaultTimeout()
|
||||||
Expect(session.OutputToString()).To(Not(ContainSubstring(secretsString)))
|
Expect(session.OutputToString()).To(Not(ContainSubstring(secretsString)))
|
||||||
})
|
})
|
||||||
|
|
||||||
|
It("podman commit adds exposed ports", func() {
|
||||||
|
name := "testcon"
|
||||||
|
s := podmanTest.Podman([]string{"run", "--name", name, "-p", "8080:80", ALPINE, "true"})
|
||||||
|
s.WaitWithDefaultTimeout()
|
||||||
|
Expect(s).Should(Exit(0))
|
||||||
|
|
||||||
|
newImageName := "newimage"
|
||||||
|
c := podmanTest.Podman([]string{"commit", name, newImageName})
|
||||||
|
c.WaitWithDefaultTimeout()
|
||||||
|
Expect(c).Should(Exit(0))
|
||||||
|
|
||||||
|
inspect := podmanTest.Podman([]string{"inspect", newImageName})
|
||||||
|
inspect.WaitWithDefaultTimeout()
|
||||||
|
Expect(inspect).Should(Exit(0))
|
||||||
|
images := inspect.InspectImageJSON()
|
||||||
|
Expect(images).To(HaveLen(1))
|
||||||
|
Expect(images[0].Config.ExposedPorts).To(HaveKey("80/tcp"))
|
||||||
|
|
||||||
|
name = "testcon2"
|
||||||
|
s = podmanTest.Podman([]string{"run", "--name", name, "-d", nginx})
|
||||||
|
s.WaitWithDefaultTimeout()
|
||||||
|
Expect(s).Should(Exit(0))
|
||||||
|
|
||||||
|
newImageName = "newimage2"
|
||||||
|
c = podmanTest.Podman([]string{"commit", name, newImageName})
|
||||||
|
c.WaitWithDefaultTimeout()
|
||||||
|
Expect(c).Should(Exit(0))
|
||||||
|
|
||||||
|
inspect = podmanTest.Podman([]string{"inspect", newImageName})
|
||||||
|
inspect.WaitWithDefaultTimeout()
|
||||||
|
Expect(inspect).Should(Exit(0))
|
||||||
|
images = inspect.InspectImageJSON()
|
||||||
|
Expect(images).To(HaveLen(1))
|
||||||
|
Expect(images[0].Config.ExposedPorts).To(HaveKey("80/tcp"))
|
||||||
|
})
|
||||||
})
|
})
|
||||||
|
@ -3,6 +3,7 @@ package integration
|
|||||||
import (
|
import (
|
||||||
"os"
|
"os"
|
||||||
|
|
||||||
|
"github.com/containers/podman/v3/libpod/define"
|
||||||
"github.com/containers/podman/v3/pkg/annotations"
|
"github.com/containers/podman/v3/pkg/annotations"
|
||||||
. "github.com/containers/podman/v3/test/utils"
|
. "github.com/containers/podman/v3/test/utils"
|
||||||
. "github.com/onsi/ginkgo"
|
. "github.com/onsi/ginkgo"
|
||||||
@ -43,4 +44,28 @@ var _ = Describe("Podman container inspect", func() {
|
|||||||
Expect(data[0].Config.Annotations[annotations.ContainerManager]).
|
Expect(data[0].Config.Annotations[annotations.ContainerManager]).
|
||||||
To(Equal(annotations.ContainerManagerLibpod))
|
To(Equal(annotations.ContainerManagerLibpod))
|
||||||
})
|
})
|
||||||
|
|
||||||
|
It("podman inspect shows exposed ports", func() {
|
||||||
|
name := "testcon"
|
||||||
|
session := podmanTest.Podman([]string{"run", "-d", "--stop-timeout", "0", "--expose", "8080/udp", "--name", name, ALPINE, "sleep", "inf"})
|
||||||
|
session.WaitWithDefaultTimeout()
|
||||||
|
Expect(session).Should(Exit(0))
|
||||||
|
data := podmanTest.InspectContainer(name)
|
||||||
|
|
||||||
|
Expect(data).To(HaveLen(1))
|
||||||
|
Expect(data[0].NetworkSettings.Ports).
|
||||||
|
To(Equal(map[string][]define.InspectHostPort{"8080/udp": nil}))
|
||||||
|
})
|
||||||
|
|
||||||
|
It("podman inspect shows exposed ports on image", func() {
|
||||||
|
name := "testcon"
|
||||||
|
session := podmanTest.Podman([]string{"run", "-d", "--expose", "8080", "--name", name, nginx})
|
||||||
|
session.WaitWithDefaultTimeout()
|
||||||
|
Expect(session).Should(Exit(0))
|
||||||
|
|
||||||
|
data := podmanTest.InspectContainer(name)
|
||||||
|
Expect(data).To(HaveLen(1))
|
||||||
|
Expect(data[0].NetworkSettings.Ports).
|
||||||
|
To(Equal(map[string][]define.InspectHostPort{"80/tcp": nil, "8080/tcp": nil}))
|
||||||
|
})
|
||||||
})
|
})
|
||||||
|
Reference in New Issue
Block a user