Skip to content

Commit 7aa8ccd

Browse files
committed
setup crio networking for build containers
1 parent 54305b0 commit 7aa8ccd

File tree

4 files changed

+105
-16
lines changed

4 files changed

+105
-16
lines changed

pkg/build/builder/docker.go

Lines changed: 7 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -297,6 +297,11 @@ func (d *DockerBuilder) dockerBuild(dir string, tag string, secrets []buildapi.S
297297
return err
298298
}
299299

300+
network, resolvConfHostPath, err := getContainerNetworkMode()
301+
if err != nil {
302+
return err
303+
}
304+
300305
opts := docker.BuildImageOptions{
301306
Name: tag,
302307
RmTmpContainer: true,
@@ -305,7 +310,8 @@ func (d *DockerBuilder) dockerBuild(dir string, tag string, secrets []buildapi.S
305310
NoCache: noCache,
306311
Pull: forcePull,
307312
BuildArgs: buildArgs,
308-
NetworkMode: string(getDockerNetworkMode()),
313+
NetworkMode: network,
314+
BuildBinds: fmt.Sprintf("[\"%s:/etc/resolv.conf\"]", resolvConfHostPath),
309315
}
310316

311317
// Though we are capped on memory and cpu at the cgroup parent level,

pkg/build/builder/sti.go

Lines changed: 10 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -166,6 +166,11 @@ func (s *S2IBuilder) Build() error {
166166
}
167167
}
168168

169+
networkMode, resolvConfHostPath, err := getContainerNetworkMode()
170+
if err != nil {
171+
return err
172+
}
173+
169174
config := &s2iapi.Config{
170175
// Save some processing time by not cleaning up (the container will go away anyway)
171176
PreserveWorkingDir: true,
@@ -182,7 +187,7 @@ func (s *S2IBuilder) Build() error {
182187

183188
Environment: buildEnvVars(s.build, sourceInfo),
184189
Labels: s2iBuildLabels(s.build, sourceInfo),
185-
DockerNetworkMode: getDockerNetworkMode(),
190+
DockerNetworkMode: s2iapi.DockerNetworkMode(networkMode),
186191

187192
Source: &s2igit.URL{URL: url.URL{Path: srcDir}, Type: s2igit.URLTypeLocal},
188193
ContextDir: contextDir,
@@ -197,6 +202,10 @@ func (s *S2IBuilder) Build() error {
197202
BlockOnBuild: true,
198203
}
199204

205+
if len(resolvConfHostPath) != 0 {
206+
config.BuildVolumes = []string{fmt.Sprintf("%s:/etc/resolv.conf", resolvConfHostPath)}
207+
}
208+
200209
if s.build.Spec.Strategy.SourceStrategy.ForcePull {
201210
glog.V(4).Infof("With force pull true, setting policies to %s", s2iapi.PullAlways)
202211
config.BuilderPullPolicy = s2iapi.PullAlways

pkg/build/builder/util.go

Lines changed: 86 additions & 12 deletions
Original file line numberDiff line numberDiff line change
@@ -20,17 +20,28 @@ import (
2020

2121
var (
2222
// procCGroupPattern is a regular expression that parses the entries in /proc/self/cgroup
23-
procCGroupPattern = regexp.MustCompile(`\d+:([a-z_,]+):/.*/(docker-|)([a-z0-9]+).*`)
23+
procCGroupPattern = regexp.MustCompile(`\d+:([a-z_,]+):/.*/(\w+-|)([a-z0-9]+).*`)
24+
25+
// pidPattern is a regexp to match the pid provided in /proc/1/sched inside a container
26+
pidPattern = regexp.MustCompile(`.*?\((\d+)`)
27+
28+
// resolvConfigPattern is a regexp to match the /etc/resolv.conf mount info in /proc/1/mountinfo
29+
resolvConfPattern = regexp.MustCompile(`.*?(/.*?) /etc/resolv\.conf `)
2430
)
2531

2632
// readNetClsCGroup parses /proc/self/cgroup in order to determine the container id that can be used
27-
// the network namespace that this process is running on.
28-
func readNetClsCGroup(reader io.Reader) string {
29-
cgroups := make(map[string]string)
33+
// the network namespace that this process is running on, it returns the cgroup and container type
34+
// (docker vs crio).
35+
func readNetClsCGroup(reader io.Reader) (string, string) {
36+
37+
containerType := "docker"
3038

39+
cgroups := make(map[string]string)
3140
scanner := bufio.NewScanner(reader)
3241
for scanner.Scan() {
3342
if match := procCGroupPattern.FindStringSubmatch(scanner.Text()); match != nil {
43+
containerType = match[2]
44+
3445
list := strings.Split(match[1], ",")
3546
containerId := match[3]
3647
if len(list) > 0 {
@@ -46,26 +57,89 @@ func readNetClsCGroup(reader io.Reader) string {
4657
names := []string{"net_cls", "cpu"}
4758
for _, group := range names {
4859
if value, ok := cgroups[group]; ok {
49-
return value
60+
return value, containerType
5061
}
5162
}
5263

53-
return ""
64+
return "", containerType
65+
}
66+
67+
// readResolveConfHostPath determines the path to the resolv.conf file for this
68+
// container, as it exists on the host machine. (/etc/resolv.conf is mounted
69+
// into the container from the host path).
70+
func readResolvConfHostPath() (string, error) {
71+
// find the /etc/resolv.conf host path based on what is mounted into this
72+
// container.
73+
resolvConf, err := os.Open("/proc/1/mountinfo")
74+
if err != nil {
75+
return "", err
76+
}
77+
defer resolvConf.Close()
78+
79+
scanner := bufio.NewScanner(resolvConf)
80+
for scanner.Scan() {
81+
if match := resolvConfPattern.FindStringSubmatch(scanner.Text()); match != nil {
82+
// don't allow the path to contain quote, comma, or colon as these could be used
83+
// to escape the bindmount argument we are passing to docker and mount other
84+
// filepaths from the host.
85+
if strings.ContainsAny(match[1], "\",:") {
86+
return "", fmt.Errorf("/etc/resolv.conf path from host contains invalid characters (',', '\"', or ':')")
87+
}
88+
return match[1], nil
89+
}
90+
}
91+
return "", fmt.Errorf("Unable to determine /etc/resolv.conf hostpath")
5492
}
5593

56-
// getDockerNetworkMode determines whether the builder is running as a container
94+
// readPid determines the actual host pid of the pid 1 process in this container
95+
func readPid() (string, error) {
96+
// get pid from /proc/1/sched , e.g.: "java (8151, #threads: 53)"
97+
pidFile, err := os.Open("/proc/1/sched")
98+
if err != nil {
99+
return "", err
100+
}
101+
defer pidFile.Close()
102+
103+
pidLine, err := bufio.NewReader(pidFile).ReadString('\n')
104+
if err != nil {
105+
return "", err
106+
}
107+
match := pidPattern.FindStringSubmatch(pidLine)
108+
if match == nil {
109+
return "", fmt.Errorf("Unable to determine pid from %s", pidLine)
110+
}
111+
return match[1], nil
112+
}
113+
114+
// getContainerNetworkMode determines whether the builder is running as a container
57115
// by examining /proc/self/cgroup. This context is then passed to source-to-image.
58-
func getDockerNetworkMode() s2iapi.DockerNetworkMode {
116+
// It returns a suitable argument for NetworkMode. If the container platform is
117+
// CRI-O, it also returns a path for /etc/resolv.conf, suitable for bindmounting.
118+
func getContainerNetworkMode() (string, string, error) {
59119
file, err := os.Open("/proc/self/cgroup")
60120
if err != nil {
61-
return ""
121+
return "", "", err
62122
}
63123
defer file.Close()
64124

65-
if id := readNetClsCGroup(file); id != "" {
66-
return s2iapi.NewDockerNetworkModeContainer(id)
125+
resolvConfHostPath, err := readResolvConfHostPath()
126+
if err != nil {
127+
return "", "", err
128+
}
129+
130+
if id, containerType := readNetClsCGroup(file); id != "" {
131+
glog.V(5).Infof("container type=%s", containerType)
132+
if containerType != "crio-" {
133+
return s2iapi.DockerNetworkModeContainerPrefix + id, resolvConfHostPath, nil
134+
}
135+
136+
pid, err := readPid()
137+
if err != nil {
138+
return "", "", err
139+
}
140+
return fmt.Sprintf("netns:/proc/%s/ns/net", pid), fmt.Sprintf("/var/run" + resolvConfHostPath), nil
67141
}
68-
return ""
142+
return "", "", nil
69143
}
70144

71145
// GetCGroupLimits returns a struct populated with cgroup limit values gathered

pkg/build/builder/util_test.go

Lines changed: 2 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -19,7 +19,7 @@ func TestCGroups_CentOS7_Docker1_7(t *testing.T) {
1919
1:name=systemd:/system.slice/docker.service
2020
`
2121
buffer := bytes.NewBufferString(example)
22-
containerId := readNetClsCGroup(buffer)
22+
containerId, _ := readNetClsCGroup(buffer)
2323

2424
if containerId != "5617ed7e7e487d2c4dd2e013e361109b4eceabfe3fa8c7aea9e37498b1aed5fa" {
2525
t.Errorf("got %s, expected 5617ed7e7e487d2c4dd2e013e361109b4eceabfe3fa8c7aea9e37498b1aed5fa", containerId)
@@ -38,7 +38,7 @@ func TestCGroups_Ubuntu_Docker1_9(t *testing.T) {
3838
3:cpuset:/docker/bfea6eb2d60179355e370a5d277d496eb0fe75d9a5a47c267221e87dbbbbc93b
3939
2:name=systemd:/`
4040
buffer := bytes.NewBufferString(example)
41-
containerId := readNetClsCGroup(buffer)
41+
containerId, _ := readNetClsCGroup(buffer)
4242

4343
if containerId != "bfea6eb2d60179355e370a5d277d496eb0fe75d9a5a47c267221e87dbbbbc93b" {
4444
t.Errorf("got %s, expected bfea6eb2d60179355e370a5d277d496eb0fe75d9a5a47c267221e87dbbbbc93b", containerId)

0 commit comments

Comments
 (0)