Skip to content

Commit 4d1f3c4

Browse files
committed
feature: add container's network files
Signed-off-by: Eric Li <[email protected]>
1 parent 76c9e6f commit 4d1f3c4

File tree

9 files changed

+203
-45
lines changed

9 files changed

+203
-45
lines changed

apis/swagger.yml

Lines changed: 5 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -1787,6 +1787,11 @@ definitions:
17871787
type: "boolean"
17881788
x-nullable: false
17891789
default: true
1790+
DisableNetworkFiles:
1791+
description: "Whether to generate the network files(/etc/hostname, /etc/hosts and /etc/resolv.conf) for container."
1792+
type: "boolean"
1793+
x-nullable: false
1794+
default: false
17901795
ExposedPorts:
17911796
description: "An object mapping ports to an empty object in the form:`{<port>/<tcp|udp>: {}}`"
17921797
type: "object"

apis/types/container_config.go

Lines changed: 5 additions & 0 deletions
Some generated files are not rendered by default. Learn more about customizing how changed files appear on GitHub.

cli/common_flags.go

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -34,6 +34,7 @@ func addCommonFlags(flagSet *pflag.FlagSet) *container {
3434
flagSet.StringVar(&c.entrypoint, "entrypoint", "", "Overwrite the default ENTRYPOINT of the image")
3535
flagSet.StringSliceVarP(&c.env, "env", "e", nil, "Set environment variables for container")
3636
flagSet.StringVar(&c.hostname, "hostname", "", "Set container's hostname")
37+
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")
3738

3839
// Intel RDT
3940
flagSet.StringVar(&c.IntelRdtL3Cbm, "intel-rdt-l3-cbm", "", "Limit container resource for Intel RDT/CAT which introduced in Linux 4.10 kernel")

cli/container.go

Lines changed: 29 additions & 27 deletions
Original file line numberDiff line numberDiff line change
@@ -10,19 +10,20 @@ import (
1010
)
1111

1212
type container struct {
13-
labels []string
14-
name string
15-
tty bool
16-
volume []string
17-
volumesFrom []string
18-
runtime string
19-
env []string
20-
entrypoint string
21-
workdir string
22-
user string
23-
groupAdd []string
24-
hostname string
25-
rm bool
13+
labels []string
14+
name string
15+
tty bool
16+
volume []string
17+
volumesFrom []string
18+
runtime string
19+
env []string
20+
entrypoint string
21+
workdir string
22+
user string
23+
groupAdd []string
24+
hostname string
25+
rm bool
26+
disableNetworkFiles bool
2627

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

174175
config := &types.ContainerCreateConfig{
175176
ContainerConfig: types.ContainerConfig{
176-
Tty: c.tty,
177-
Env: c.env,
178-
Entrypoint: strings.Fields(c.entrypoint),
179-
WorkingDir: c.workdir,
180-
User: c.user,
181-
Hostname: strfmt.Hostname(c.hostname),
182-
Labels: labels,
183-
Rich: c.rich,
184-
RichMode: c.richMode,
185-
InitScript: c.initScript,
186-
ExposedPorts: ports,
187-
DiskQuota: diskQuota,
188-
QuotaID: c.quotaID,
189-
SpecAnnotation: specAnnotation,
177+
Tty: c.tty,
178+
Env: c.env,
179+
Entrypoint: strings.Fields(c.entrypoint),
180+
WorkingDir: c.workdir,
181+
User: c.user,
182+
Hostname: strfmt.Hostname(c.hostname),
183+
DisableNetworkFiles: c.disableNetworkFiles,
184+
Labels: labels,
185+
Rich: c.rich,
186+
RichMode: c.richMode,
187+
InitScript: c.initScript,
188+
ExposedPorts: ports,
189+
DiskQuota: diskQuota,
190+
QuotaID: c.quotaID,
191+
SpecAnnotation: specAnnotation,
190192
},
191193

192194
HostConfig: &types.HostConfig{

cri/v1alpha1/cri_utils.go

Lines changed: 3 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -216,6 +216,9 @@ func applySandboxSecurityContext(lc *runtime.LinuxPodSandboxConfig, config *apit
216216

217217
// applySandboxLinuxOptions applies LinuxPodSandboxConfig to pouch's HostConfig and ContainerCreateConfig.
218218
func applySandboxLinuxOptions(hc *apitypes.HostConfig, lc *runtime.LinuxPodSandboxConfig, createConfig *apitypes.ContainerCreateConfig, image string) error {
219+
// apply the sandbox network_mode, "none" is default.
220+
hc.NetworkMode = namespaceModeNone
221+
219222
if lc == nil {
220223
return nil
221224
}

cri/v1alpha2/cri_utils.go

Lines changed: 3 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -216,6 +216,9 @@ func applySandboxSecurityContext(lc *runtime.LinuxPodSandboxConfig, config *apit
216216

217217
// applySandboxLinuxOptions applies LinuxPodSandboxConfig to pouch's HostConfig and ContainerCreateConfig.
218218
func applySandboxLinuxOptions(hc *apitypes.HostConfig, lc *runtime.LinuxPodSandboxConfig, createConfig *apitypes.ContainerCreateConfig, image string) error {
219+
// apply the sandbox network_mode, "none" is default.
220+
hc.NetworkMode = namespaceModeNone
221+
219222
if lc == nil {
220223
return nil
221224
}

daemon/mgr/container.go

Lines changed: 43 additions & 18 deletions
Original file line numberDiff line numberDiff line change
@@ -250,6 +250,12 @@ func (mgr *ContainerManager) Create(ctx context.Context, name string, config *ty
250250
return nil, errors.Wrap(errtypes.ErrAlreadyExisted, "container name: "+name)
251251
}
252252

253+
// set hostname.
254+
if config.Hostname.String() == "" {
255+
// if hostname is empty, take the part of id as the hostname
256+
config.Hostname = strfmt.Hostname(id[:12])
257+
}
258+
253259
// set container runtime
254260
if config.HostConfig.Runtime == "" {
255261
config.HostConfig.Runtime = mgr.Config.DefaultRuntime
@@ -322,13 +328,12 @@ func (mgr *ContainerManager) Create(ctx context.Context, name string, config *ty
322328
networkMode := config.HostConfig.NetworkMode
323329
if networkMode == "" {
324330
config.HostConfig.NetworkMode = "bridge"
325-
container.Config.NetworkDisabled = true
326331
}
327332
container.NetworkSettings = new(types.NetworkSettings)
328333
if len(config.NetworkingConfig.EndpointsConfig) > 0 {
329334
container.NetworkSettings.Networks = config.NetworkingConfig.EndpointsConfig
330335
}
331-
if container.NetworkSettings.Networks == nil && networkMode != "" && !IsContainer(networkMode) {
336+
if container.NetworkSettings.Networks == nil && !IsContainer(config.HostConfig.NetworkMode) {
332337
container.NetworkSettings.Networks = make(map[string]*types.EndpointSettings)
333338
container.NetworkSettings.Networks[config.HostConfig.NetworkMode] = new(types.EndpointSettings)
334339
}
@@ -454,33 +459,53 @@ func (mgr *ContainerManager) start(ctx context.Context, c *Container, detachKeys
454459
c.ResolvConfPath = origContainer.ResolvConfPath
455460
c.Config.Hostname = origContainer.Config.Hostname
456461
c.Config.Domainname = origContainer.Config.Domainname
457-
}
462+
} else {
463+
// initialise host network mode
464+
if IsHost(networkMode) {
465+
hostname, err := os.Hostname()
466+
if err != nil {
467+
return err
468+
}
469+
c.Config.Hostname = strfmt.Hostname(hostname)
470+
}
458471

459-
// initialise host network mode
460-
if IsHost(networkMode) {
461-
hostname, err := os.Hostname()
462-
if err != nil {
472+
// build the network related path.
473+
if err := mgr.buildNetworkRelatedPath(c); err != nil {
463474
return err
464475
}
465-
c.Config.Hostname = strfmt.Hostname(hostname)
466-
}
467476

468-
// initialise network endpoint
469-
if c.NetworkSettings != nil {
470-
for name, endpointSetting := range c.NetworkSettings.Networks {
471-
endpoint := mgr.buildContainerEndpoint(c)
472-
endpoint.Name = name
473-
endpoint.EndpointConfig = endpointSetting
474-
if _, err := mgr.NetworkMgr.EndpointCreate(ctx, endpoint); err != nil {
475-
logrus.Errorf("failed to create endpoint: %v", err)
476-
return err
477+
// initialise network endpoint
478+
if c.NetworkSettings != nil {
479+
for name, endpointSetting := range c.NetworkSettings.Networks {
480+
endpoint := mgr.buildContainerEndpoint(c)
481+
endpoint.Name = name
482+
endpoint.EndpointConfig = endpointSetting
483+
if _, err := mgr.NetworkMgr.EndpointCreate(ctx, endpoint); err != nil {
484+
logrus.Errorf("failed to create endpoint: %v", err)
485+
return err
486+
}
477487
}
478488
}
479489
}
480490

481491
return mgr.createContainerdContainer(ctx, c)
482492
}
483493

494+
// buildNetworkRelatedPath builds the network related path.
495+
func (mgr *ContainerManager) buildNetworkRelatedPath(c *Container) error {
496+
// set the hosts file path.
497+
c.HostsPath = path.Join(mgr.Store.Path(c.ID), "hosts")
498+
499+
// set the resolv.conf file path.
500+
c.ResolvConfPath = path.Join(mgr.Store.Path(c.ID), "resolv.conf")
501+
502+
// set the hostname file path.
503+
c.HostnamePath = path.Join(mgr.Store.Path(c.ID), "hostname")
504+
505+
// write the hostname file, other files are filled by libnetwork.
506+
return ioutil.WriteFile(c.HostnamePath, []byte(c.Config.Hostname+"\n"), 0644)
507+
}
508+
484509
func (mgr *ContainerManager) createContainerdContainer(ctx context.Context, c *Container) error {
485510
// CgroupParent from HostConfig will be first priority to use,
486511
// then will be value from mgr.Config.CgroupParent

daemon/mgr/spec_mount.go

Lines changed: 68 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -3,8 +3,12 @@ package mgr
33
import (
44
"context"
55
"fmt"
6+
"os"
7+
8+
"github.com/alibaba/pouch/apis/types"
69

710
specs "github.com/opencontainers/runtime-spec/specs-go"
11+
"github.com/sirupsen/logrus"
812
)
913

1014
func clearReadonly(m *specs.Mount) {
@@ -31,6 +35,11 @@ func setupMounts(ctx context.Context, c *Container, s *specs.Spec) error {
3135
return nil
3236
}
3337
for _, mp := range c.Mounts {
38+
if trySetupNetworkMount(mp, c) {
39+
// ignore the network mount, we will handle it later.
40+
continue
41+
}
42+
3443
// check duplicate mountpoint
3544
for _, sm := range mounts {
3645
if sm.Destination == mp.Destination {
@@ -69,6 +78,12 @@ func setupMounts(ctx context.Context, c *Container, s *specs.Spec) error {
6978
Options: opts,
7079
})
7180
}
81+
82+
// if disable hostfiles, we will not mount the hosts files into container.
83+
if !c.Config.DisableNetworkFiles {
84+
mounts = append(mounts, generateNetworkMounts(c)...)
85+
}
86+
7287
s.Mounts = mounts
7388

7489
if c.HostConfig.Privileged {
@@ -83,3 +98,56 @@ func setupMounts(ctx context.Context, c *Container, s *specs.Spec) error {
8398
}
8499
return nil
85100
}
101+
102+
// generateNetworkMounts will generate network mounts.
103+
func generateNetworkMounts(c *Container) []specs.Mount {
104+
mounts := make([]specs.Mount, 0)
105+
106+
fileBinds := []struct {
107+
Name string
108+
Source string
109+
Dest string
110+
}{
111+
{"HostnamePath", c.HostnamePath, "/etc/hostname"},
112+
{"HostsPath", c.HostsPath, "/etc/hosts"},
113+
{"ResolvConfPath", c.ResolvConfPath, "/etc/resolv.conf"},
114+
}
115+
116+
for _, bind := range fileBinds {
117+
if bind.Source != "" {
118+
_, err := os.Stat(bind.Source)
119+
if err != nil {
120+
logrus.Warnf("%s set to %s, but stat error: %v, skip it", bind.Name, bind.Source, err)
121+
} else {
122+
mounts = append(mounts, specs.Mount{
123+
Source: bind.Source,
124+
Destination: bind.Dest,
125+
Type: "bind",
126+
Options: []string{"rbind", "rprivate"},
127+
})
128+
}
129+
}
130+
}
131+
132+
return mounts
133+
}
134+
135+
// trySetupNetworkMount will try to set network mount.
136+
func trySetupNetworkMount(mount *types.MountPoint, c *Container) bool {
137+
if mount.Destination == "/etc/hostname" {
138+
c.HostnamePath = mount.Source
139+
return true
140+
}
141+
142+
if mount.Destination == "/etc/hosts" {
143+
c.HostsPath = mount.Source
144+
return true
145+
}
146+
147+
if mount.Destination == "/etc/resolv.conf" {
148+
c.ResolvConfPath = mount.Source
149+
return true
150+
}
151+
152+
return false
153+
}

test/cli_run_test.go

Lines changed: 46 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -332,3 +332,49 @@ func (suite *PouchRunSuite) TestRunWithRM(c *check.C) {
332332
output := command.PouchRun("inspect", cname).Stderr()
333333
c.Assert(util.PartialEqual(output, cname+": not found"), check.IsNil)
334334
}
335+
336+
// TestRunWithDisableNetworkFiles is to verify running container with disable-network-files flag
337+
func (suite *PouchRunSuite) TestRunWithDisableNetworkFiles(c *check.C) {
338+
339+
// Run a container with disable-network-files flag
340+
341+
cname1 := "RunWithDisableNetworkFiles"
342+
res := command.PouchRun("run", "--disable-network-files", "--name", cname1,
343+
busyboxImage, "ls", "/etc")
344+
defer DelContainerForceMultyTime(c, cname1)
345+
346+
res.Assert(c, icmd.Success)
347+
348+
output := res.Stdout()
349+
if strings.Contains(output, "hostname") {
350+
c.Fatal("expected no /etc/hostname, but the file exists")
351+
}
352+
353+
if strings.Contains(output, "hosts") {
354+
c.Fatal("expected no /etc/hosts, but the file exists")
355+
}
356+
357+
if strings.Contains(output, "resolv.conf") {
358+
// ignore check the existence of /etc/resolv.conf, because the busybox
359+
// contains the file.
360+
}
361+
362+
// Run a container without disable-network-files flag
363+
364+
cname2 := "RunWithoutDisableNetworkFiles"
365+
res = command.PouchRun("run", "--name", cname2, busyboxImage, "ls", "/etc")
366+
defer DelContainerForceMultyTime(c, cname2)
367+
368+
output = res.Stdout()
369+
if !strings.Contains(output, "hostname") {
370+
c.Fatal("expected /etc/hostname, but the file does not exist")
371+
}
372+
373+
if !strings.Contains(output, "hosts") {
374+
c.Fatal("expected /etc/hosts, but the file does not exist")
375+
}
376+
377+
if !strings.Contains(output, "resolv.conf") {
378+
c.Fatal("expected /etc/resolv.conf, but the file does not exist")
379+
}
380+
}

0 commit comments

Comments
 (0)