X Tutup
Skip to content

Commit dc964de

Browse files
committed
Add windows implmenetation
Signed-off-by: Lantao Liu <lantaol@google.com>
1 parent bbcf564 commit dc964de

21 files changed

+1123
-360
lines changed

pkg/config/config_windows.go

Lines changed: 47 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -18,7 +18,53 @@ limitations under the License.
1818

1919
package config
2020

21+
import (
22+
"os"
23+
"path/filepath"
24+
25+
"github.com/containerd/containerd"
26+
"k8s.io/kubernetes/pkg/kubelet/server/streaming"
27+
)
28+
2129
// DefaultConfig returns default configurations of cri plugin.
2230
func DefaultConfig() PluginConfig {
23-
return PluginConfig{}
31+
return PluginConfig{
32+
CniConfig: CniConfig{
33+
NetworkPluginBinDir: filepath.Join(os.Getenv("ProgramFiles"), "containerd", "cni", "bin"),
34+
NetworkPluginConfDir: filepath.Join(os.Getenv("ProgramFiles"), "containerd", "cni", "conf"),
35+
NetworkPluginMaxConfNum: 1,
36+
NetworkPluginConfTemplate: "",
37+
},
38+
ContainerdConfig: ContainerdConfig{
39+
Snapshotter: containerd.DefaultSnapshotter,
40+
DefaultRuntimeName: "runhcs-wcow-process",
41+
NoPivot: false,
42+
Runtimes: map[string]Runtime{
43+
"runhcs-wcow-process": {
44+
Type: "io.containerd.runhcs.v1",
45+
},
46+
},
47+
},
48+
DisableTCPService: true,
49+
StreamServerAddress: "127.0.0.1",
50+
StreamServerPort: "0",
51+
StreamIdleTimeout: streaming.DefaultConfig.StreamIdleTimeout.String(), // 4 hour
52+
EnableTLSStreaming: false,
53+
X509KeyPairStreaming: X509KeyPairStreaming{
54+
TLSKeyFile: "",
55+
TLSCertFile: "",
56+
},
57+
SandboxImage: "mcr.microsoft.com/k8s/core/pause:1.0.0",
58+
StatsCollectPeriod: 10,
59+
MaxContainerLogLineSize: 16 * 1024,
60+
Registry: Registry{
61+
Mirrors: map[string]Mirror{
62+
"docker.io": {
63+
Endpoints: []string{"https://registry-1.docker.io"},
64+
},
65+
},
66+
},
67+
MaxConcurrentDownloads: 3,
68+
// TODO(windows): Add platform specific config, so that most common defaults can be shared.
69+
}
2470
}

pkg/containerd/opts/spec.go

Lines changed: 6 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -42,6 +42,12 @@ func WithRelativeRoot(root string) oci.SpecOpts {
4242
}
4343
}
4444

45+
// WithoutRoot sets the root to nil for the container.
46+
func WithoutRoot(ctx context.Context, client oci.Client, c *containers.Container, s *runtimespec.Spec) error {
47+
s.Root = nil
48+
return nil
49+
}
50+
4551
// WithProcessArgs sets the process args on the spec based on the image and runtime config
4652
func WithProcessArgs(config *runtime.ContainerConfig, image *imagespec.ImageConfig) oci.SpecOpts {
4753
return func(ctx context.Context, client oci.Client, c *containers.Container, s *runtimespec.Spec) (err error) {

pkg/containerd/opts/spec_unix.go

Lines changed: 0 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -137,7 +137,6 @@ func WithMounts(osi osinterface.OS, config *runtime.ContainerConfig, extra []*ru
137137
mounts = append(mounts, e)
138138
}
139139
}
140-
// ---
141140

142141
// Sort mounts in number of parts. This ensures that high level mounts don't
143142
// shadow other mounts.
Lines changed: 174 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,174 @@
1+
// +build windows
2+
3+
/*
4+
Copyright The containerd Authors.
5+
6+
Licensed under the Apache License, Version 2.0 (the "License");
7+
you may not use this file except in compliance with the License.
8+
You may obtain a copy of the License at
9+
10+
http://www.apache.org/licenses/LICENSE-2.0
11+
12+
Unless required by applicable law or agreed to in writing, software
13+
distributed under the License is distributed on an "AS IS" BASIS,
14+
WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
15+
See the License for the specific language governing permissions and
16+
limitations under the License.
17+
*/
18+
19+
package opts
20+
21+
import (
22+
"context"
23+
"path/filepath"
24+
"sort"
25+
26+
"github.com/containerd/containerd/containers"
27+
"github.com/containerd/containerd/oci"
28+
runtimespec "github.com/opencontainers/runtime-spec/specs-go"
29+
"github.com/pkg/errors"
30+
runtime "k8s.io/cri-api/pkg/apis/runtime/v1alpha2"
31+
32+
osinterface "github.com/containerd/cri/pkg/os"
33+
)
34+
35+
// WithWindowsNetworkNamespace sets windows network namespace for container.
36+
// TODO(windows): Move this into container/containerd.
37+
func WithWindowsNetworkNamespace(path string) oci.SpecOpts {
38+
return func(ctx context.Context, client oci.Client, c *containers.Container, s *runtimespec.Spec) error {
39+
if s.Windows == nil {
40+
s.Windows = &runtimespec.Windows{}
41+
}
42+
if s.Windows.Network == nil {
43+
s.Windows.Network = &runtimespec.WindowsNetwork{}
44+
}
45+
s.Windows.Network.NetworkNamespace = path
46+
return nil
47+
}
48+
}
49+
50+
// WithWindowsMounts sorts and adds runtime and CRI mounts to the spec for
51+
// windows container.
52+
func WithWindowsMounts(osi osinterface.OS, config *runtime.ContainerConfig, extra []*runtime.Mount) oci.SpecOpts {
53+
return func(ctx context.Context, client oci.Client, _ *containers.Container, s *runtimespec.Spec) error {
54+
// mergeMounts merge CRI mounts with extra mounts. If a mount destination
55+
// is mounted by both a CRI mount and an extra mount, the CRI mount will
56+
// be kept.
57+
var (
58+
criMounts = config.GetMounts()
59+
mounts = append([]*runtime.Mount{}, criMounts...)
60+
)
61+
// Copy all mounts from extra mounts, except for mounts overriden by CRI.
62+
for _, e := range extra {
63+
found := false
64+
for _, c := range criMounts {
65+
if filepath.Clean(e.ContainerPath) == filepath.Clean(c.ContainerPath) {
66+
found = true
67+
break
68+
}
69+
}
70+
if !found {
71+
mounts = append(mounts, e)
72+
}
73+
}
74+
75+
// Sort mounts in number of parts. This ensures that high level mounts don't
76+
// shadow other mounts.
77+
sort.Sort(orderedMounts(mounts))
78+
79+
// Copy all mounts from default mounts, except for
80+
// - mounts overriden by supplied mount;
81+
// - all mounts under /dev if a supplied /dev is present.
82+
mountSet := make(map[string]struct{})
83+
for _, m := range mounts {
84+
mountSet[filepath.Clean(m.ContainerPath)] = struct{}{}
85+
}
86+
87+
defaultMounts := s.Mounts
88+
s.Mounts = nil
89+
90+
for _, m := range defaultMounts {
91+
dst := filepath.Clean(m.Destination)
92+
if _, ok := mountSet[dst]; ok {
93+
// filter out mount overridden by a supplied mount
94+
continue
95+
}
96+
s.Mounts = append(s.Mounts, m)
97+
}
98+
99+
for _, mount := range mounts {
100+
var (
101+
dst = mount.GetContainerPath()
102+
src = mount.GetHostPath()
103+
)
104+
// TODO(windows): Support special mount sources, e.g. named pipe.
105+
// Create the host path if it doesn't exist.
106+
if _, err := osi.Stat(src); err != nil {
107+
// If the source doesn't exist, return an error instead
108+
// of creating the source. This aligns with Docker's
109+
// behavior on windows.
110+
return errors.Wrapf(err, "failed to stat %q", src)
111+
}
112+
src, err := osi.ResolveSymbolicLink(src)
113+
if err != nil {
114+
return errors.Wrapf(err, "failed to resolve symlink %q", src)
115+
}
116+
117+
var options []string
118+
// NOTE(random-liu): we don't change all mounts to `ro` when root filesystem
119+
// is readonly. This is different from docker's behavior, but make more sense.
120+
if mount.GetReadonly() {
121+
options = append(options, "ro")
122+
} else {
123+
options = append(options, "rw")
124+
}
125+
s.Mounts = append(s.Mounts, runtimespec.Mount{
126+
Source: src,
127+
Destination: dst,
128+
Options: options,
129+
})
130+
}
131+
return nil
132+
}
133+
}
134+
135+
// WithWindowsResources sets the provided resource restrictions for windows.
136+
func WithWindowsResources(resources *runtime.WindowsContainerResources) oci.SpecOpts {
137+
return func(ctx context.Context, client oci.Client, c *containers.Container, s *runtimespec.Spec) error {
138+
if resources == nil {
139+
return nil
140+
}
141+
if s.Windows == nil {
142+
s.Windows = &runtimespec.Windows{}
143+
}
144+
if s.Windows.Resources == nil {
145+
s.Windows.Resources = &runtimespec.WindowsResources{}
146+
}
147+
if s.Windows.Resources.CPU == nil {
148+
s.Windows.Resources.CPU = &runtimespec.WindowsCPUResources{}
149+
}
150+
if s.Windows.Resources.Memory == nil {
151+
s.Windows.Resources.Memory = &runtimespec.WindowsMemoryResources{}
152+
}
153+
154+
var (
155+
count = uint64(resources.GetCpuCount())
156+
shares = uint16(resources.GetCpuShares())
157+
max = uint16(resources.GetCpuMaximum())
158+
limit = uint64(resources.GetMemoryLimitInBytes())
159+
)
160+
if count != 0 {
161+
s.Windows.Resources.CPU.Count = &count
162+
}
163+
if shares != 0 {
164+
s.Windows.Resources.CPU.Shares = &shares
165+
}
166+
if max != 0 {
167+
s.Windows.Resources.CPU.Maximum = &max
168+
}
169+
if limit != 0 {
170+
s.Windows.Resources.Memory.Limit = &limit
171+
}
172+
return nil
173+
}
174+
}

pkg/netns/netns_windows.go

Lines changed: 38 additions & 10 deletions
Original file line numberDiff line numberDiff line change
@@ -18,33 +18,61 @@ limitations under the License.
1818

1919
package netns
2020

21-
// TODO(windows): Implement netns for windows.
22-
// NetNS holds network namespace.
21+
import "github.com/Microsoft/hcsshim/hcn"
22+
23+
// NetNS holds network namespace for sandbox
2324
type NetNS struct {
25+
path string
2426
}
2527

26-
// NewNetNS creates a network namespace.
28+
// NewNetNS creates a network namespace for the sandbox
2729
func NewNetNS() (*NetNS, error) {
28-
return nil, nil
30+
temp := hcn.HostComputeNamespace{}
31+
hcnNamespace, err := temp.Create()
32+
if err != nil {
33+
return nil, err
34+
}
35+
36+
return &NetNS{path: string(hcnNamespace.Id)}, nil
2937
}
3038

3139
// LoadNetNS loads existing network namespace.
3240
func LoadNetNS(path string) *NetNS {
33-
return nil
41+
return &NetNS{path: path}
3442
}
3543

36-
// Remove removes network namepace. Remove is idempotent, meaning it might
37-
// be invoked multiple times and provides consistent result.
44+
// Remove removes network namepace if it exists and not closed. Remove is idempotent,
45+
// meaning it might be invoked multiple times and provides consistent result.
3846
func (n *NetNS) Remove() error {
39-
return nil
47+
hcnNamespace, err := hcn.GetNamespaceByID(n.path)
48+
if err != nil {
49+
if hcn.IsNotFoundError(err) {
50+
return nil
51+
}
52+
return err
53+
}
54+
err = hcnNamespace.Delete()
55+
if err == nil || hcn.IsNotFoundError(err) {
56+
return nil
57+
}
58+
return err
4059
}
4160

4261
// Closed checks whether the network namespace has been closed.
4362
func (n *NetNS) Closed() (bool, error) {
44-
return false, nil
63+
_, err := hcn.GetNamespaceByID(n.path)
64+
if err == nil {
65+
return false, nil
66+
}
67+
if hcn.IsNotFoundError(err) {
68+
return true, nil
69+
}
70+
return false, err
4571
}
4672

4773
// GetPath returns network namespace path for sandbox container
4874
func (n *NetNS) GetPath() string {
49-
return ""
75+
return n.path
5076
}
77+
78+
// NOTE: Do function is not supported.

pkg/server/container_create.go

Lines changed: 1 addition & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -284,8 +284,7 @@ func (c *criService) volumeMounts(containerRootDir string, criMounts []*runtime.
284284
}
285285

286286
// runtimeSpec returns a default runtime spec used in cri-containerd.
287-
// TODO(windows): Remove nolint after windows starts using this helper.
288-
func runtimeSpec(id string, opts ...oci.SpecOpts) (*runtimespec.Spec, error) { // nolint: deadcode, unused
287+
func runtimeSpec(id string, opts ...oci.SpecOpts) (*runtimespec.Spec, error) {
289288
// GenerateSpec needs namespace.
290289
ctx := ctrdutil.NamespacedContext()
291290
spec, err := oci.GenerateSpec(ctx, nil, &containers.Container{ID: id}, opts...)

0 commit comments

Comments
 (0)
X Tutup