Skip to content

Commit

Permalink
Merge pull request #1403 from shaloulcy/add_network_files
Browse files Browse the repository at this point in the history
feature: add container's network files
  • Loading branch information
HusterWan authored Jun 1, 2018
2 parents b056a27 + db46eff commit d41da05
Show file tree
Hide file tree
Showing 9 changed files with 200 additions and 45 deletions.
5 changes: 5 additions & 0 deletions apis/swagger.yml
Original file line number Diff line number Diff line change
Expand Up @@ -1839,6 +1839,11 @@ definitions:
type: "boolean"
x-nullable: false
default: true
DisableNetworkFiles:
description: "Whether to generate the network files(/etc/hostname, /etc/hosts and /etc/resolv.conf) for container."
type: "boolean"
x-nullable: false
default: false
ExposedPorts:
description: "An object mapping ports to an empty object in the form:`{<port>/<tcp|udp>: {}}`"
type: "object"
Expand Down
5 changes: 5 additions & 0 deletions apis/types/container_config.go

Some generated files are not rendered by default. Learn more about how customized files appear on GitHub.

1 change: 1 addition & 0 deletions cli/common_flags.go
Original file line number Diff line number Diff line change
Expand Up @@ -34,6 +34,7 @@ func addCommonFlags(flagSet *pflag.FlagSet) *container {
flagSet.StringVar(&c.entrypoint, "entrypoint", "", "Overwrite the default ENTRYPOINT of the image")
flagSet.StringSliceVarP(&c.env, "env", "e", nil, "Set environment variables for container")
flagSet.StringVar(&c.hostname, "hostname", "", "Set container's hostname")
flagSet.BoolVar(&c.disableNetworkFiles, "disable-network-files", false, "Disable the generation of network files(/etc/hostname, /etc/hosts and /etc/resolv.conf) for container. If true, no network files will be generated. Default false")

// Intel RDT
flagSet.StringVar(&c.IntelRdtL3Cbm, "intel-rdt-l3-cbm", "", "Limit container resource for Intel RDT/CAT which introduced in Linux 4.10 kernel")
Expand Down
56 changes: 29 additions & 27 deletions cli/container.go
Original file line number Diff line number Diff line change
Expand Up @@ -10,19 +10,20 @@ import (
)

type container struct {
labels []string
name string
tty bool
volume []string
volumesFrom []string
runtime string
env []string
entrypoint string
workdir string
user string
groupAdd []string
hostname string
rm bool
labels []string
name string
tty bool
volume []string
volumesFrom []string
runtime string
env []string
entrypoint string
workdir string
user string
groupAdd []string
hostname string
rm bool
disableNetworkFiles bool

blkioWeight uint16
blkioWeightDevice WeightDevice
Expand Down Expand Up @@ -173,20 +174,21 @@ func (c *container) config() (*types.ContainerCreateConfig, error) {

config := &types.ContainerCreateConfig{
ContainerConfig: types.ContainerConfig{
Tty: c.tty,
Env: c.env,
Entrypoint: strings.Fields(c.entrypoint),
WorkingDir: c.workdir,
User: c.user,
Hostname: strfmt.Hostname(c.hostname),
Labels: labels,
Rich: c.rich,
RichMode: c.richMode,
InitScript: c.initScript,
ExposedPorts: ports,
DiskQuota: diskQuota,
QuotaID: c.quotaID,
SpecAnnotation: specAnnotation,
Tty: c.tty,
Env: c.env,
Entrypoint: strings.Fields(c.entrypoint),
WorkingDir: c.workdir,
User: c.user,
Hostname: strfmt.Hostname(c.hostname),
DisableNetworkFiles: c.disableNetworkFiles,
Labels: labels,
Rich: c.rich,
RichMode: c.richMode,
InitScript: c.initScript,
ExposedPorts: ports,
DiskQuota: diskQuota,
QuotaID: c.quotaID,
SpecAnnotation: specAnnotation,
},

HostConfig: &types.HostConfig{
Expand Down
3 changes: 3 additions & 0 deletions cri/v1alpha1/cri_utils.go
Original file line number Diff line number Diff line change
Expand Up @@ -216,6 +216,9 @@ func applySandboxSecurityContext(lc *runtime.LinuxPodSandboxConfig, config *apit

// applySandboxLinuxOptions applies LinuxPodSandboxConfig to pouch's HostConfig and ContainerCreateConfig.
func applySandboxLinuxOptions(hc *apitypes.HostConfig, lc *runtime.LinuxPodSandboxConfig, createConfig *apitypes.ContainerCreateConfig, image string) error {
// apply the sandbox network_mode, "none" is default.
hc.NetworkMode = namespaceModeNone

if lc == nil {
return nil
}
Expand Down
3 changes: 3 additions & 0 deletions cri/v1alpha2/cri_utils.go
Original file line number Diff line number Diff line change
Expand Up @@ -216,6 +216,9 @@ func applySandboxSecurityContext(lc *runtime.LinuxPodSandboxConfig, config *apit

// applySandboxLinuxOptions applies LinuxPodSandboxConfig to pouch's HostConfig and ContainerCreateConfig.
func applySandboxLinuxOptions(hc *apitypes.HostConfig, lc *runtime.LinuxPodSandboxConfig, createConfig *apitypes.ContainerCreateConfig, image string) error {
// apply the sandbox network_mode, "none" is default.
hc.NetworkMode = namespaceModeNone

if lc == nil {
return nil
}
Expand Down
61 changes: 43 additions & 18 deletions daemon/mgr/container.go
Original file line number Diff line number Diff line change
Expand Up @@ -256,6 +256,12 @@ func (mgr *ContainerManager) Create(ctx context.Context, name string, config *ty
return nil, errors.Wrap(errtypes.ErrAlreadyExisted, "container name: "+name)
}

// set hostname.
if config.Hostname.String() == "" {
// if hostname is empty, take the part of id as the hostname
config.Hostname = strfmt.Hostname(id[:12])
}

// set container runtime
if config.HostConfig.Runtime == "" {
config.HostConfig.Runtime = mgr.Config.DefaultRuntime
Expand Down Expand Up @@ -328,13 +334,12 @@ func (mgr *ContainerManager) Create(ctx context.Context, name string, config *ty
networkMode := config.HostConfig.NetworkMode
if networkMode == "" {
config.HostConfig.NetworkMode = "bridge"
container.Config.NetworkDisabled = true
}
container.NetworkSettings = new(types.NetworkSettings)
if len(config.NetworkingConfig.EndpointsConfig) > 0 {
container.NetworkSettings.Networks = config.NetworkingConfig.EndpointsConfig
}
if container.NetworkSettings.Networks == nil && networkMode != "" && !IsContainer(networkMode) {
if container.NetworkSettings.Networks == nil && !IsContainer(config.HostConfig.NetworkMode) {
container.NetworkSettings.Networks = make(map[string]*types.EndpointSettings)
container.NetworkSettings.Networks[config.HostConfig.NetworkMode] = new(types.EndpointSettings)
}
Expand Down Expand Up @@ -460,33 +465,53 @@ func (mgr *ContainerManager) start(ctx context.Context, c *Container, detachKeys
c.ResolvConfPath = origContainer.ResolvConfPath
c.Config.Hostname = origContainer.Config.Hostname
c.Config.Domainname = origContainer.Config.Domainname
}
} else {
// initialise host network mode
if IsHost(networkMode) {
hostname, err := os.Hostname()
if err != nil {
return err
}
c.Config.Hostname = strfmt.Hostname(hostname)
}

// initialise host network mode
if IsHost(networkMode) {
hostname, err := os.Hostname()
if err != nil {
// build the network related path.
if err := mgr.buildNetworkRelatedPath(c); err != nil {
return err
}
c.Config.Hostname = strfmt.Hostname(hostname)
}

// initialise network endpoint
if c.NetworkSettings != nil {
for name, endpointSetting := range c.NetworkSettings.Networks {
endpoint := mgr.buildContainerEndpoint(c)
endpoint.Name = name
endpoint.EndpointConfig = endpointSetting
if _, err := mgr.NetworkMgr.EndpointCreate(ctx, endpoint); err != nil {
logrus.Errorf("failed to create endpoint: %v", err)
return err
// initialise network endpoint
if c.NetworkSettings != nil {
for name, endpointSetting := range c.NetworkSettings.Networks {
endpoint := mgr.buildContainerEndpoint(c)
endpoint.Name = name
endpoint.EndpointConfig = endpointSetting
if _, err := mgr.NetworkMgr.EndpointCreate(ctx, endpoint); err != nil {
logrus.Errorf("failed to create endpoint: %v", err)
return err
}
}
}
}

return mgr.createContainerdContainer(ctx, c)
}

// buildNetworkRelatedPath builds the network related path.
func (mgr *ContainerManager) buildNetworkRelatedPath(c *Container) error {
// set the hosts file path.
c.HostsPath = path.Join(mgr.Store.Path(c.ID), "hosts")

// set the resolv.conf file path.
c.ResolvConfPath = path.Join(mgr.Store.Path(c.ID), "resolv.conf")

// set the hostname file path.
c.HostnamePath = path.Join(mgr.Store.Path(c.ID), "hostname")

// write the hostname file, other files are filled by libnetwork.
return ioutil.WriteFile(c.HostnamePath, []byte(c.Config.Hostname+"\n"), 0644)
}

func (mgr *ContainerManager) createContainerdContainer(ctx context.Context, c *Container) error {
// CgroupParent from HostConfig will be first priority to use,
// then will be value from mgr.Config.CgroupParent
Expand Down
68 changes: 68 additions & 0 deletions daemon/mgr/spec_mount.go
Original file line number Diff line number Diff line change
Expand Up @@ -3,8 +3,12 @@ package mgr
import (
"context"
"fmt"
"os"

"github.com/alibaba/pouch/apis/types"

specs "github.com/opencontainers/runtime-spec/specs-go"
"github.com/sirupsen/logrus"
)

func clearReadonly(m *specs.Mount) {
Expand All @@ -31,6 +35,11 @@ func setupMounts(ctx context.Context, c *Container, s *specs.Spec) error {
return nil
}
for _, mp := range c.Mounts {
if trySetupNetworkMount(mp, c) {
// ignore the network mount, we will handle it later.
continue
}

// check duplicate mountpoint
for _, sm := range mounts {
if sm.Destination == mp.Destination {
Expand Down Expand Up @@ -69,6 +78,12 @@ func setupMounts(ctx context.Context, c *Container, s *specs.Spec) error {
Options: opts,
})
}

// if disable hostfiles, we will not mount the hosts files into container.
if !c.Config.DisableNetworkFiles {
mounts = append(mounts, generateNetworkMounts(c)...)
}

s.Mounts = mounts

if c.HostConfig.Privileged {
Expand All @@ -83,3 +98,56 @@ func setupMounts(ctx context.Context, c *Container, s *specs.Spec) error {
}
return nil
}

// generateNetworkMounts will generate network mounts.
func generateNetworkMounts(c *Container) []specs.Mount {
mounts := make([]specs.Mount, 0)

fileBinds := []struct {
Name string
Source string
Dest string
}{
{"HostnamePath", c.HostnamePath, "/etc/hostname"},
{"HostsPath", c.HostsPath, "/etc/hosts"},
{"ResolvConfPath", c.ResolvConfPath, "/etc/resolv.conf"},
}

for _, bind := range fileBinds {
if bind.Source != "" {
_, err := os.Stat(bind.Source)
if err != nil {
logrus.Warnf("%s set to %s, but stat error: %v, skip it", bind.Name, bind.Source, err)
} else {
mounts = append(mounts, specs.Mount{
Source: bind.Source,
Destination: bind.Dest,
Type: "bind",
Options: []string{"rbind", "rprivate"},
})
}
}
}

return mounts
}

// trySetupNetworkMount will try to set network mount.
func trySetupNetworkMount(mount *types.MountPoint, c *Container) bool {
if mount.Destination == "/etc/hostname" {
c.HostnamePath = mount.Source
return true
}

if mount.Destination == "/etc/hosts" {
c.HostsPath = mount.Source
return true
}

if mount.Destination == "/etc/resolv.conf" {
c.ResolvConfPath = mount.Source
return true
}

return false
}
43 changes: 43 additions & 0 deletions test/cli_run_test.go
Original file line number Diff line number Diff line change
Expand Up @@ -332,3 +332,46 @@ func (suite *PouchRunSuite) TestRunWithRM(c *check.C) {
output := command.PouchRun("inspect", cname).Stderr()
c.Assert(util.PartialEqual(output, cname+": not found"), check.IsNil)
}

// TestRunWithDisableNetworkFiles is to verify running container with disable-network-files flag.
func (suite *PouchRunSuite) TestRunWithDisableNetworkFiles(c *check.C) {
// Run a container with disable-network-files flag
cname1 := "RunWithDisableNetworkFiles"
res := command.PouchRun("run", "--disable-network-files", "--name", cname1,
busyboxImage, "ls", "/etc")
defer DelContainerForceMultyTime(c, cname1)

res.Assert(c, icmd.Success)
output := res.Stdout()
if strings.Contains(output, "hostname") {
c.Fatal("expected no /etc/hostname, but the file exists")
}

if strings.Contains(output, "hosts") {
c.Fatal("expected no /etc/hosts, but the file exists")
}

if strings.Contains(output, "resolv.conf") {
// ignore checking the existence of /etc/resolv.conf, because the busybox
// contains the file.
}

// Run a container without disable-network-files flag
cname2 := "RunWithoutDisableNetworkFiles"
res = command.PouchRun("run", "--name", cname2, busyboxImage, "ls", "/etc")
defer DelContainerForceMultyTime(c, cname2)

res.Assert(c, icmd.Success)
output = res.Stdout()
if !strings.Contains(output, "hostname") {
c.Fatal("expected /etc/hostname, but the file does not exist")
}

if !strings.Contains(output, "hosts") {
c.Fatal("expected /etc/hosts, but the file does not exist")
}

if !strings.Contains(output, "resolv.conf") {
c.Fatal("expected /etc/resolv.conf, but the file does not exist")
}
}

0 comments on commit d41da05

Please sign in to comment.