mirror of
https://github.com/k3s-io/kubernetes.git
synced 2025-07-29 06:27:05 +00:00
Merge pull request #7543 from yifan-gu/pod_manifest
kubelet/rkt: Add routines for converting kubelet pod to rkt pod.
This commit is contained in:
commit
262c34e7db
128
pkg/kubelet/rkt/cap.go
Normal file
128
pkg/kubelet/rkt/cap.go
Normal file
@ -0,0 +1,128 @@
|
|||||||
|
/*
|
||||||
|
Copyright 2015 Google Inc. All rights reserved.
|
||||||
|
|
||||||
|
Licensed under the Apache License, Version 2.0 (the "License");
|
||||||
|
you may not use this file except in compliance with the License.
|
||||||
|
You may obtain a copy of the License at
|
||||||
|
|
||||||
|
http://www.apache.org/licenses/LICENSE-2.0
|
||||||
|
|
||||||
|
Unless required by applicable law or agreed to in writing, software
|
||||||
|
distributed under the License is distributed on an "AS IS" BASIS,
|
||||||
|
WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
|
||||||
|
See the License for the specific language governing permissions and
|
||||||
|
limitations under the License.
|
||||||
|
*/
|
||||||
|
|
||||||
|
package rkt
|
||||||
|
|
||||||
|
import (
|
||||||
|
"fmt"
|
||||||
|
"strings"
|
||||||
|
|
||||||
|
"github.com/GoogleCloudPlatform/kubernetes/pkg/api"
|
||||||
|
)
|
||||||
|
|
||||||
|
// TODO(yifan): Export this to higher level package.
|
||||||
|
const (
|
||||||
|
CAP_CHOWN = iota
|
||||||
|
CAP_DAC_OVERRIDE
|
||||||
|
CAP_DAC_READ_SEARCH
|
||||||
|
CAP_FOWNER
|
||||||
|
CAP_FSETID
|
||||||
|
CAP_KILL
|
||||||
|
CAP_SETGID
|
||||||
|
CAP_SETUID
|
||||||
|
CAP_SETPCAP
|
||||||
|
CAP_LINUX_IMMUTABLE
|
||||||
|
CAP_NET_BIND_SERVICE
|
||||||
|
CAP_NET_BROADCAST
|
||||||
|
CAP_NET_ADMIN
|
||||||
|
CAP_NET_RAW
|
||||||
|
CAP_IPC_LOCK
|
||||||
|
CAP_IPC_OWNER
|
||||||
|
CAP_SYS_MODULE
|
||||||
|
CAP_SYS_RAWIO
|
||||||
|
CAP_SYS_CHROOT
|
||||||
|
CAP_SYS_PTRACE
|
||||||
|
CAP_SYS_PACCT
|
||||||
|
CAP_SYS_ADMIN
|
||||||
|
CAP_SYS_BOOT
|
||||||
|
CAP_SYS_NICE
|
||||||
|
CAP_SYS_RESOURCE
|
||||||
|
CAP_SYS_TIME
|
||||||
|
CAP_SYS_TTY_CONFIG
|
||||||
|
CAP_MKNOD
|
||||||
|
CAP_LEASE
|
||||||
|
CAP_AUDIT_WRITE
|
||||||
|
CAP_AUDIT_CONTROL
|
||||||
|
CAP_SETFCAP
|
||||||
|
CAP_MAC_OVERRIDE
|
||||||
|
CAP_MAC_ADMIN
|
||||||
|
CAP_SYSLOG
|
||||||
|
CAP_WAKE_ALARM
|
||||||
|
CAP_BLOCK_SUSPEND
|
||||||
|
CAP_AUDIT_READ
|
||||||
|
)
|
||||||
|
|
||||||
|
// TODO(yifan): Export this to higher level package.
|
||||||
|
var capabilityList = map[int]string{
|
||||||
|
CAP_CHOWN: "CAP_CHOWN",
|
||||||
|
CAP_DAC_OVERRIDE: "CAP_DAC_OVERRIDE",
|
||||||
|
CAP_DAC_READ_SEARCH: "CAP_DAC_READ_SEARCH",
|
||||||
|
CAP_FOWNER: "CAP_FOWNER",
|
||||||
|
CAP_FSETID: "CAP_FSETID",
|
||||||
|
CAP_KILL: "CAP_KILL",
|
||||||
|
CAP_SETGID: "CAP_SETGID",
|
||||||
|
CAP_SETUID: "CAP_SETUID",
|
||||||
|
CAP_SETPCAP: "CAP_SETPCAP",
|
||||||
|
CAP_LINUX_IMMUTABLE: "CAP_LINUX_IMMUTABLE",
|
||||||
|
CAP_NET_BIND_SERVICE: "CAP_NET_BIND_SERVICE",
|
||||||
|
CAP_NET_BROADCAST: "CAP_NET_BROADCAST",
|
||||||
|
CAP_NET_ADMIN: "CAP_NET_ADMIN",
|
||||||
|
CAP_NET_RAW: "CAP_NET_RAW",
|
||||||
|
CAP_IPC_LOCK: "CAP_IPC_LOCK",
|
||||||
|
CAP_IPC_OWNER: "CAP_IPC_OWNER",
|
||||||
|
CAP_SYS_MODULE: "CAP_SYS_MODULE",
|
||||||
|
CAP_SYS_RAWIO: "CAP_SYS_RAWIO",
|
||||||
|
CAP_SYS_CHROOT: "CAP_SYS_CHROOT",
|
||||||
|
CAP_SYS_PTRACE: "CAP_SYS_PTRACE",
|
||||||
|
CAP_SYS_PACCT: "CAP_SYS_PACCT",
|
||||||
|
CAP_SYS_ADMIN: "CAP_SYS_ADMIN",
|
||||||
|
CAP_SYS_BOOT: "CAP_SYS_BOOT",
|
||||||
|
CAP_SYS_NICE: "CAP_SYS_NICE",
|
||||||
|
CAP_SYS_RESOURCE: "CAP_SYS_RESOURCE",
|
||||||
|
CAP_SYS_TIME: "CAP_SYS_TIME",
|
||||||
|
CAP_SYS_TTY_CONFIG: "CAP_SYS_TTY_CONFIG",
|
||||||
|
CAP_MKNOD: "CAP_MKNOD",
|
||||||
|
CAP_LEASE: "CAP_LEASE",
|
||||||
|
CAP_AUDIT_WRITE: "CAP_AUDIT_WRITE",
|
||||||
|
CAP_AUDIT_CONTROL: "CAP_AUDIT_CONTROL",
|
||||||
|
CAP_SETFCAP: "CAP_SETFCAP",
|
||||||
|
CAP_MAC_OVERRIDE: "CAP_MAC_OVERRIDE",
|
||||||
|
CAP_MAC_ADMIN: "CAP_MAC_ADMIN",
|
||||||
|
CAP_SYSLOG: "CAP_SYSLOG",
|
||||||
|
CAP_WAKE_ALARM: "CAP_WAKE_ALARM",
|
||||||
|
CAP_BLOCK_SUSPEND: "CAP_BLOCK_SUSPEND",
|
||||||
|
CAP_AUDIT_READ: "CAP_AUDIT_READ",
|
||||||
|
}
|
||||||
|
|
||||||
|
// getAllCapabilities returns the capability list with all capabilities.
|
||||||
|
func getAllCapabilities() string {
|
||||||
|
var capabilities []string
|
||||||
|
for _, cap := range capabilityList {
|
||||||
|
capabilities = append(capabilities, fmt.Sprintf("%q", cap))
|
||||||
|
}
|
||||||
|
return strings.Join(capabilities, ",")
|
||||||
|
}
|
||||||
|
|
||||||
|
// TODO(yifan): This assumes that api.CapabilityType has the form of
|
||||||
|
// "CAP_SYS_ADMIN". We need to have a formal definition for
|
||||||
|
// capabilities.
|
||||||
|
func getCapabilities(caps []api.CapabilityType) string {
|
||||||
|
var capList []string
|
||||||
|
for _, cap := range caps {
|
||||||
|
capList = append(capList, fmt.Sprintf("%q", cap))
|
||||||
|
}
|
||||||
|
return strings.Join(capList, ",")
|
||||||
|
}
|
@ -17,13 +17,20 @@ limitations under the License.
|
|||||||
package rkt
|
package rkt
|
||||||
|
|
||||||
import (
|
import (
|
||||||
|
"encoding/json"
|
||||||
"fmt"
|
"fmt"
|
||||||
"os/exec"
|
"os/exec"
|
||||||
"strings"
|
"strings"
|
||||||
|
|
||||||
|
"github.com/GoogleCloudPlatform/kubernetes/pkg/api"
|
||||||
|
"github.com/GoogleCloudPlatform/kubernetes/pkg/capabilities"
|
||||||
"github.com/GoogleCloudPlatform/kubernetes/pkg/credentialprovider"
|
"github.com/GoogleCloudPlatform/kubernetes/pkg/credentialprovider"
|
||||||
"github.com/GoogleCloudPlatform/kubernetes/pkg/types"
|
"github.com/GoogleCloudPlatform/kubernetes/pkg/types"
|
||||||
|
"github.com/GoogleCloudPlatform/kubernetes/pkg/volume"
|
||||||
|
appcschema "github.com/appc/spec/schema"
|
||||||
|
appctypes "github.com/appc/spec/schema/types"
|
||||||
"github.com/coreos/go-systemd/dbus"
|
"github.com/coreos/go-systemd/dbus"
|
||||||
|
"github.com/coreos/rkt/store"
|
||||||
"github.com/golang/glog"
|
"github.com/golang/glog"
|
||||||
)
|
)
|
||||||
|
|
||||||
@ -77,15 +84,13 @@ func New(config *Config) (*Runtime, error) {
|
|||||||
|
|
||||||
systemd, err := dbus.New()
|
systemd, err := dbus.New()
|
||||||
if err != nil {
|
if err != nil {
|
||||||
glog.Errorf("rkt: Cannot connect to dbus: %v", err)
|
return nil, fmt.Errorf("cannot connect to dbus: %v", err)
|
||||||
return nil, err
|
|
||||||
}
|
}
|
||||||
|
|
||||||
// Test if rkt binary is in $PATH.
|
// Test if rkt binary is in $PATH.
|
||||||
absPath, err := exec.LookPath(rktBinName)
|
absPath, err := exec.LookPath(rktBinName)
|
||||||
if err != nil {
|
if err != nil {
|
||||||
glog.Errorf("rkt: Cannot find rkt binary: %v", err)
|
return nil, fmt.Errorf("cannot find rkt binary: %v", err)
|
||||||
return nil, err
|
|
||||||
}
|
}
|
||||||
|
|
||||||
rkt := &Runtime{
|
rkt := &Runtime{
|
||||||
@ -134,3 +139,246 @@ func makePodServiceFileName(uid types.UID) string {
|
|||||||
// TODO(yifan): Revisit this later, decide whether we want to use UID.
|
// TODO(yifan): Revisit this later, decide whether we want to use UID.
|
||||||
return fmt.Sprintf("%s_%s.service", kubernetesUnitPrefix, uid)
|
return fmt.Sprintf("%s_%s.service", kubernetesUnitPrefix, uid)
|
||||||
}
|
}
|
||||||
|
|
||||||
|
type resource struct {
|
||||||
|
limit string
|
||||||
|
request string
|
||||||
|
}
|
||||||
|
|
||||||
|
// rawValue converts a string to *json.RawMessage
|
||||||
|
func rawValue(value string) *json.RawMessage {
|
||||||
|
msg := json.RawMessage(value)
|
||||||
|
return &msg
|
||||||
|
}
|
||||||
|
|
||||||
|
// setIsolators overrides the isolators of the pod manifest if necessary.
|
||||||
|
func setIsolators(app *appctypes.App, c *api.Container) error {
|
||||||
|
if len(c.Capabilities.Add) > 0 || len(c.Capabilities.Drop) > 0 || len(c.Resources.Limits) > 0 || len(c.Resources.Requests) > 0 {
|
||||||
|
app.Isolators = []appctypes.Isolator{}
|
||||||
|
}
|
||||||
|
|
||||||
|
// Retained capabilities/privileged.
|
||||||
|
privileged := false
|
||||||
|
if capabilities.Get().AllowPrivileged {
|
||||||
|
privileged = c.Privileged
|
||||||
|
} else if c.Privileged {
|
||||||
|
return fmt.Errorf("privileged is disallowed globally")
|
||||||
|
}
|
||||||
|
var addCaps string
|
||||||
|
if privileged {
|
||||||
|
addCaps = getAllCapabilities()
|
||||||
|
} else {
|
||||||
|
addCaps = getCapabilities(c.Capabilities.Add)
|
||||||
|
}
|
||||||
|
if len(addCaps) > 0 {
|
||||||
|
// TODO(yifan): Replace with constructor, see:
|
||||||
|
// https://github.com/appc/spec/issues/268
|
||||||
|
isolator := appctypes.Isolator{
|
||||||
|
Name: "os/linux/capabilities-retain-set",
|
||||||
|
ValueRaw: rawValue(fmt.Sprintf(`{"set":[%s]}`, addCaps)),
|
||||||
|
}
|
||||||
|
app.Isolators = append(app.Isolators, isolator)
|
||||||
|
}
|
||||||
|
|
||||||
|
// Removed capabilities.
|
||||||
|
dropCaps := getCapabilities(c.Capabilities.Drop)
|
||||||
|
if len(dropCaps) > 0 {
|
||||||
|
// TODO(yifan): Replace with constructor, see:
|
||||||
|
// https://github.com/appc/spec/issues/268
|
||||||
|
isolator := appctypes.Isolator{
|
||||||
|
Name: "os/linux/capabilities-remove-set",
|
||||||
|
ValueRaw: rawValue(fmt.Sprintf(`{"set":[%s]}`, dropCaps)),
|
||||||
|
}
|
||||||
|
app.Isolators = append(app.Isolators, isolator)
|
||||||
|
}
|
||||||
|
|
||||||
|
// Resources.
|
||||||
|
resources := make(map[api.ResourceName]resource)
|
||||||
|
for name, quantity := range c.Resources.Limits {
|
||||||
|
resources[name] = resource{limit: quantity.String()}
|
||||||
|
}
|
||||||
|
for name, quantity := range c.Resources.Requests {
|
||||||
|
r, ok := resources[name]
|
||||||
|
if !ok {
|
||||||
|
r = resource{}
|
||||||
|
}
|
||||||
|
r.request = quantity.String()
|
||||||
|
resources[name] = r
|
||||||
|
}
|
||||||
|
var acName appctypes.ACName
|
||||||
|
for name, res := range resources {
|
||||||
|
switch name {
|
||||||
|
case api.ResourceCPU:
|
||||||
|
acName = "resource/cpu"
|
||||||
|
case api.ResourceMemory:
|
||||||
|
acName = "resource/memory"
|
||||||
|
default:
|
||||||
|
return fmt.Errorf("resource type not supported: %v", name)
|
||||||
|
}
|
||||||
|
// TODO(yifan): Replace with constructor, see:
|
||||||
|
// https://github.com/appc/spec/issues/268
|
||||||
|
isolator := appctypes.Isolator{
|
||||||
|
Name: acName,
|
||||||
|
ValueRaw: rawValue(fmt.Sprintf(`{"request":%q,"limit":%q}`, res.request, res.limit)),
|
||||||
|
}
|
||||||
|
app.Isolators = append(app.Isolators, isolator)
|
||||||
|
}
|
||||||
|
return nil
|
||||||
|
}
|
||||||
|
|
||||||
|
// setApp overrides the app's fields if any of them are specified in the
|
||||||
|
// container's spec.
|
||||||
|
func setApp(app *appctypes.App, c *api.Container) error {
|
||||||
|
// Override the exec.
|
||||||
|
// TOOD(yifan): Revisit this for the overriding rule.
|
||||||
|
if len(c.Command) > 0 || len(c.Args) > 0 {
|
||||||
|
app.Exec = append(c.Command, c.Args...)
|
||||||
|
}
|
||||||
|
|
||||||
|
// TODO(yifan): Use non-root user in the future, see:
|
||||||
|
// https://github.com/coreos/rkt/issues/820
|
||||||
|
app.User, app.Group = "0", "0"
|
||||||
|
|
||||||
|
// Override the working directory.
|
||||||
|
if len(c.WorkingDir) > 0 {
|
||||||
|
app.WorkingDirectory = c.WorkingDir
|
||||||
|
}
|
||||||
|
|
||||||
|
// Override the environment.
|
||||||
|
// TODO(yifan): Use RunContainerOptions.
|
||||||
|
if len(c.Env) > 0 {
|
||||||
|
app.Environment = []appctypes.EnvironmentVariable{}
|
||||||
|
}
|
||||||
|
for _, env := range c.Env {
|
||||||
|
app.Environment = append(app.Environment, appctypes.EnvironmentVariable{
|
||||||
|
Name: env.Name,
|
||||||
|
Value: env.Value,
|
||||||
|
})
|
||||||
|
}
|
||||||
|
|
||||||
|
// Override the mount points.
|
||||||
|
if len(c.VolumeMounts) > 0 {
|
||||||
|
app.MountPoints = []appctypes.MountPoint{}
|
||||||
|
}
|
||||||
|
for _, m := range c.VolumeMounts {
|
||||||
|
mountPointName, err := appctypes.NewACName(m.Name)
|
||||||
|
if err != nil {
|
||||||
|
return err
|
||||||
|
}
|
||||||
|
app.MountPoints = append(app.MountPoints, appctypes.MountPoint{
|
||||||
|
Name: *mountPointName,
|
||||||
|
Path: m.MountPath,
|
||||||
|
ReadOnly: m.ReadOnly,
|
||||||
|
})
|
||||||
|
}
|
||||||
|
|
||||||
|
// Override the ports.
|
||||||
|
if len(c.Ports) > 0 {
|
||||||
|
app.Ports = []appctypes.Port{}
|
||||||
|
}
|
||||||
|
for _, p := range c.Ports {
|
||||||
|
portName, err := appctypes.NewACName(p.Name)
|
||||||
|
if err != nil {
|
||||||
|
return err
|
||||||
|
}
|
||||||
|
app.Ports = append(app.Ports, appctypes.Port{
|
||||||
|
Name: *portName,
|
||||||
|
Protocol: string(p.Protocol),
|
||||||
|
Port: uint(p.ContainerPort),
|
||||||
|
})
|
||||||
|
}
|
||||||
|
|
||||||
|
// Override isolators.
|
||||||
|
return setIsolators(app, c)
|
||||||
|
}
|
||||||
|
|
||||||
|
// makePodManifest transforms a kubelet pod spec to the rkt pod manifest.
|
||||||
|
// TODO(yifan): Use the RunContainerOptions generated by GenerateRunContainerOptions().
|
||||||
|
func (r *Runtime) makePodManifest(pod *api.Pod, volumeMap map[string]volume.Volume) (*appcschema.PodManifest, error) {
|
||||||
|
manifest := appcschema.BlankPodManifest()
|
||||||
|
|
||||||
|
// Get the image manifests, assume they are already in the cas,
|
||||||
|
// and extract the app field from the image and to be the 'base app'.
|
||||||
|
//
|
||||||
|
// We do this is because we will fully replace the image manifest's app
|
||||||
|
// with the pod manifest's app in rkt runtime. See below:
|
||||||
|
//
|
||||||
|
// https://github.com/coreos/rkt/issues/723.
|
||||||
|
//
|
||||||
|
s, err := store.NewStore(rktDataDir)
|
||||||
|
if err != nil {
|
||||||
|
return nil, fmt.Errorf("cannot open store: %v", err)
|
||||||
|
}
|
||||||
|
for _, c := range pod.Spec.Containers {
|
||||||
|
// Assume we are running docker images for now, see #7203.
|
||||||
|
imageID, err := r.getImageID(c.Image)
|
||||||
|
if err != nil {
|
||||||
|
return nil, fmt.Errorf("cannot get image ID for %q: %v", c.Image, err)
|
||||||
|
}
|
||||||
|
hash, err := appctypes.NewHash(imageID)
|
||||||
|
if err != nil {
|
||||||
|
return nil, err
|
||||||
|
}
|
||||||
|
|
||||||
|
im, err := s.GetImageManifest(hash.String())
|
||||||
|
if err != nil {
|
||||||
|
return nil, fmt.Errorf("cannot get image manifest: %v", err)
|
||||||
|
}
|
||||||
|
|
||||||
|
// Override the image manifest's app and store it in the pod manifest.
|
||||||
|
app := im.App
|
||||||
|
if err := setApp(app, &c); err != nil {
|
||||||
|
return nil, err
|
||||||
|
}
|
||||||
|
manifest.Apps = append(manifest.Apps, appcschema.RuntimeApp{
|
||||||
|
Name: im.Name,
|
||||||
|
Image: appcschema.RuntimeImage{ID: *hash},
|
||||||
|
App: app,
|
||||||
|
})
|
||||||
|
}
|
||||||
|
|
||||||
|
// Set global volumes.
|
||||||
|
for name, volume := range volumeMap {
|
||||||
|
volName, err := appctypes.NewACName(name)
|
||||||
|
if err != nil {
|
||||||
|
return nil, fmt.Errorf("cannot use the volume's name %q as ACName: %v", name, err)
|
||||||
|
}
|
||||||
|
manifest.Volumes = append(manifest.Volumes, appctypes.Volume{
|
||||||
|
Name: *volName,
|
||||||
|
Kind: "host",
|
||||||
|
Source: volume.GetPath(),
|
||||||
|
})
|
||||||
|
}
|
||||||
|
|
||||||
|
// Set global ports.
|
||||||
|
for _, c := range pod.Spec.Containers {
|
||||||
|
for _, port := range c.Ports {
|
||||||
|
portName, err := appctypes.NewACName(port.Name)
|
||||||
|
if err != nil {
|
||||||
|
return nil, fmt.Errorf("cannot use the port's name %q as ACName: %v", port.Name, err)
|
||||||
|
}
|
||||||
|
manifest.Ports = append(manifest.Ports, appctypes.ExposedPort{
|
||||||
|
Name: *portName,
|
||||||
|
HostPort: uint(port.HostPort),
|
||||||
|
})
|
||||||
|
}
|
||||||
|
}
|
||||||
|
// TODO(yifan): Set pod-level isolators once it's supported in kubernetes.
|
||||||
|
return manifest, nil
|
||||||
|
}
|
||||||
|
|
||||||
|
// TODO(yifan): Replace with 'rkt images'.
|
||||||
|
func (r *Runtime) getImageID(imageName string) (string, error) {
|
||||||
|
output, err := r.runCommand("fetch", imageName)
|
||||||
|
if err != nil {
|
||||||
|
return "", err
|
||||||
|
}
|
||||||
|
if len(output) == 0 {
|
||||||
|
return "", fmt.Errorf("no result from rkt fetch")
|
||||||
|
}
|
||||||
|
last := output[len(output)-1]
|
||||||
|
if !strings.HasPrefix(last, "sha512-") {
|
||||||
|
return "", fmt.Errorf("unexpected result: %q", last)
|
||||||
|
}
|
||||||
|
return last, nil
|
||||||
|
}
|
||||||
|
Loading…
Reference in New Issue
Block a user