mirror of
https://github.com/containers/podman
synced 2024-10-19 08:44:11 +00:00
Merge pull request #10716 from cdoern/podFlags
Podman Pod Create --cpus and --cpuset-cpus flags
This commit is contained in:
commit
3f3feaa015
|
@ -222,7 +222,6 @@ func createInit(c *cobra.Command) error {
|
||||||
}
|
}
|
||||||
cliVals.Env = env
|
cliVals.Env = env
|
||||||
}
|
}
|
||||||
|
|
||||||
if c.Flag("cgroups").Changed && cliVals.CGroupsMode == "split" && registry.IsRemote() {
|
if c.Flag("cgroups").Changed && cliVals.CGroupsMode == "split" && registry.IsRemote() {
|
||||||
return errors.Errorf("the option --cgroups=%q is not supported in remote mode", cliVals.CGroupsMode)
|
return errors.Errorf("the option --cgroups=%q is not supported in remote mode", cliVals.CGroupsMode)
|
||||||
}
|
}
|
||||||
|
@ -292,6 +291,8 @@ func createPodIfNecessary(s *specgen.SpecGenerator, netOpts *entities.NetOptions
|
||||||
Net: netOpts,
|
Net: netOpts,
|
||||||
CreateCommand: os.Args,
|
CreateCommand: os.Args,
|
||||||
Hostname: s.ContainerBasicConfig.Hostname,
|
Hostname: s.ContainerBasicConfig.Hostname,
|
||||||
|
Cpus: cliVals.CPUS,
|
||||||
|
CpusetCpus: cliVals.CPUSetCPUs,
|
||||||
}
|
}
|
||||||
// Unset config values we passed to the pod to prevent them being used twice for the container and pod.
|
// Unset config values we passed to the pod to prevent them being used twice for the container and pod.
|
||||||
s.ContainerBasicConfig.Hostname = ""
|
s.ContainerBasicConfig.Hostname = ""
|
||||||
|
|
|
@ -5,9 +5,13 @@ import (
|
||||||
"fmt"
|
"fmt"
|
||||||
"io/ioutil"
|
"io/ioutil"
|
||||||
"os"
|
"os"
|
||||||
|
"runtime"
|
||||||
|
"sort"
|
||||||
|
"strconv"
|
||||||
"strings"
|
"strings"
|
||||||
|
|
||||||
"github.com/containers/common/pkg/completion"
|
"github.com/containers/common/pkg/completion"
|
||||||
|
"github.com/containers/common/pkg/sysinfo"
|
||||||
"github.com/containers/podman/v3/cmd/podman/common"
|
"github.com/containers/podman/v3/cmd/podman/common"
|
||||||
"github.com/containers/podman/v3/cmd/podman/parse"
|
"github.com/containers/podman/v3/cmd/podman/parse"
|
||||||
"github.com/containers/podman/v3/cmd/podman/registry"
|
"github.com/containers/podman/v3/cmd/podman/registry"
|
||||||
|
@ -16,6 +20,7 @@ import (
|
||||||
"github.com/containers/podman/v3/pkg/errorhandling"
|
"github.com/containers/podman/v3/pkg/errorhandling"
|
||||||
"github.com/containers/podman/v3/pkg/specgen"
|
"github.com/containers/podman/v3/pkg/specgen"
|
||||||
"github.com/containers/podman/v3/pkg/util"
|
"github.com/containers/podman/v3/pkg/util"
|
||||||
|
"github.com/docker/docker/pkg/parsers"
|
||||||
"github.com/pkg/errors"
|
"github.com/pkg/errors"
|
||||||
"github.com/sirupsen/logrus"
|
"github.com/sirupsen/logrus"
|
||||||
"github.com/spf13/cobra"
|
"github.com/spf13/cobra"
|
||||||
|
@ -55,6 +60,14 @@ func init() {
|
||||||
|
|
||||||
common.DefineNetFlags(createCommand)
|
common.DefineNetFlags(createCommand)
|
||||||
|
|
||||||
|
cpusetflagName := "cpuset-cpus"
|
||||||
|
flags.StringVar(&createOptions.CpusetCpus, cpusetflagName, "", "CPUs in which to allow execution")
|
||||||
|
_ = createCommand.RegisterFlagCompletionFunc(cpusetflagName, completion.AutocompleteDefault)
|
||||||
|
|
||||||
|
cpusflagName := "cpus"
|
||||||
|
flags.Float64Var(&createOptions.Cpus, cpusflagName, 0.000, "set amount of CPUs for the pod")
|
||||||
|
_ = createCommand.RegisterFlagCompletionFunc(cpusflagName, completion.AutocompleteDefault)
|
||||||
|
|
||||||
cgroupParentflagName := "cgroup-parent"
|
cgroupParentflagName := "cgroup-parent"
|
||||||
flags.StringVar(&createOptions.CGroupParent, cgroupParentflagName, "", "Set parent cgroup for the pod")
|
flags.StringVar(&createOptions.CGroupParent, cgroupParentflagName, "", "Set parent cgroup for the pod")
|
||||||
_ = createCommand.RegisterFlagCompletionFunc(cgroupParentflagName, completion.AutocompleteDefault)
|
_ = createCommand.RegisterFlagCompletionFunc(cgroupParentflagName, completion.AutocompleteDefault)
|
||||||
|
@ -185,6 +198,46 @@ func create(cmd *cobra.Command, args []string) error {
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
numCPU := sysinfo.NumCPU()
|
||||||
|
if numCPU == 0 {
|
||||||
|
numCPU = runtime.NumCPU()
|
||||||
|
}
|
||||||
|
if createOptions.Cpus > float64(numCPU) {
|
||||||
|
createOptions.Cpus = float64(numCPU)
|
||||||
|
}
|
||||||
|
copy := createOptions.CpusetCpus
|
||||||
|
cpuSet := createOptions.Cpus
|
||||||
|
if cpuSet == 0 {
|
||||||
|
cpuSet = float64(sysinfo.NumCPU())
|
||||||
|
}
|
||||||
|
ret, err := parsers.ParseUintList(copy)
|
||||||
|
copy = ""
|
||||||
|
if err != nil {
|
||||||
|
errors.Wrapf(err, "could not parse list")
|
||||||
|
}
|
||||||
|
var vals []int
|
||||||
|
for ind, val := range ret {
|
||||||
|
if val {
|
||||||
|
vals = append(vals, ind)
|
||||||
|
}
|
||||||
|
}
|
||||||
|
sort.Ints(vals)
|
||||||
|
for ind, core := range vals {
|
||||||
|
if core > int(cpuSet) {
|
||||||
|
if copy == "" {
|
||||||
|
copy = "0-" + strconv.Itoa(int(cpuSet))
|
||||||
|
createOptions.CpusetCpus = copy
|
||||||
|
break
|
||||||
|
} else {
|
||||||
|
createOptions.CpusetCpus = copy
|
||||||
|
break
|
||||||
|
}
|
||||||
|
} else if ind != 0 {
|
||||||
|
copy += "," + strconv.Itoa(core)
|
||||||
|
} else {
|
||||||
|
copy = "" + strconv.Itoa(core)
|
||||||
|
}
|
||||||
|
}
|
||||||
response, err := registry.ContainerEngine().PodCreate(context.Background(), createOptions)
|
response, err := registry.ContainerEngine().PodCreate(context.Background(), createOptions)
|
||||||
if err != nil {
|
if err != nil {
|
||||||
return err
|
return err
|
||||||
|
|
|
@ -23,6 +23,22 @@ Add a host to the /etc/hosts file shared between all containers in the pod.
|
||||||
|
|
||||||
Path to cgroups under which the cgroup for the pod will be created. If the path is not absolute, the path is considered to be relative to the cgroups path of the init process. Cgroups will be created if they do not already exist.
|
Path to cgroups under which the cgroup for the pod will be created. If the path is not absolute, the path is considered to be relative to the cgroups path of the init process. Cgroups will be created if they do not already exist.
|
||||||
|
|
||||||
|
#### **--cpus**=*amount*
|
||||||
|
|
||||||
|
Set the total number of CPUs delegated to the pod. Default is 0.000 which indicates that there is no limit on computation power.
|
||||||
|
|
||||||
|
#### **--cpuset-cpus**=*amount*
|
||||||
|
|
||||||
|
Limit the CPUs to support execution. First CPU is numbered 0. Unlike --cpus this is of type string and parsed as a list of numbers
|
||||||
|
|
||||||
|
Format is 0-3,0,1
|
||||||
|
|
||||||
|
Examples of the List Format:
|
||||||
|
|
||||||
|
0-4,9 # bits 0, 1, 2, 3, 4, and 9 set
|
||||||
|
0-2,7,12-14 # bits 0, 1, 2, 7, 12, 13, and 14 set
|
||||||
|
|
||||||
|
|
||||||
#### **--dns**=*ipaddr*
|
#### **--dns**=*ipaddr*
|
||||||
|
|
||||||
Set custom DNS servers in the /etc/resolv.conf file that will be shared between all containers in the pod. A special option, "none" is allowed which disables creation of /etc/resolv.conf for the pod.
|
Set custom DNS servers in the /etc/resolv.conf file that will be shared between all containers in the pod. A special option, "none" is allowed which disables creation of /etc/resolv.conf for the pod.
|
||||||
|
|
|
@ -131,6 +131,5 @@ func (c *Container) validate() error {
|
||||||
if c.config.User == "" && (c.config.Spec.Process.User.UID != 0 || c.config.Spec.Process.User.GID != 0) {
|
if c.config.User == "" && (c.config.Spec.Process.User.UID != 0 || c.config.Spec.Process.User.GID != 0) {
|
||||||
return errors.Wrapf(define.ErrInvalidArg, "please set User explicitly via WithUser() instead of in OCI spec directly")
|
return errors.Wrapf(define.ErrInvalidArg, "please set User explicitly via WithUser() instead of in OCI spec directly")
|
||||||
}
|
}
|
||||||
|
|
||||||
return nil
|
return nil
|
||||||
}
|
}
|
||||||
|
|
|
@ -51,6 +51,12 @@ type InspectPodData struct {
|
||||||
// Containers gives a brief summary of all containers in the pod and
|
// Containers gives a brief summary of all containers in the pod and
|
||||||
// their current status.
|
// their current status.
|
||||||
Containers []InspectPodContainerInfo `json:"Containers,omitempty"`
|
Containers []InspectPodContainerInfo `json:"Containers,omitempty"`
|
||||||
|
// CPUPeriod contains the CPU period of the pod
|
||||||
|
CPUPeriod uint64 `json:"cpu_period,omitempty"`
|
||||||
|
// CPUQuota contains the CPU quota of the pod
|
||||||
|
CPUQuota int64 `json:"cpu_quota,omitempty"`
|
||||||
|
// CPUSetCPUs contains linux specific CPU data for the pod
|
||||||
|
CPUSetCPUs string `json:"cpuset_cpus,omitempty"`
|
||||||
}
|
}
|
||||||
|
|
||||||
// InspectPodInfraConfig contains the configuration of the pod's infra
|
// InspectPodInfraConfig contains the configuration of the pod's infra
|
||||||
|
@ -91,6 +97,12 @@ type InspectPodInfraConfig struct {
|
||||||
Networks []string
|
Networks []string
|
||||||
// NetworkOptions are additional options for each network
|
// NetworkOptions are additional options for each network
|
||||||
NetworkOptions map[string][]string
|
NetworkOptions map[string][]string
|
||||||
|
// CPUPeriod contains the CPU period of the pod
|
||||||
|
CPUPeriod uint64 `json:"cpu_period,omitempty"`
|
||||||
|
// CPUQuota contains the CPU quota of the pod
|
||||||
|
CPUQuota int64 `json:"cpu_quota,omitempty"`
|
||||||
|
// CPUSetCPUs contains linux specific CPU data for the container
|
||||||
|
CPUSetCPUs string `json:"cpuset_cpus,omitempty"`
|
||||||
}
|
}
|
||||||
|
|
||||||
// InspectPodContainerInfo contains information on a container in a pod.
|
// InspectPodContainerInfo contains information on a container in a pod.
|
||||||
|
|
|
@ -20,6 +20,7 @@ import (
|
||||||
"github.com/containers/storage"
|
"github.com/containers/storage"
|
||||||
"github.com/containers/storage/pkg/idtools"
|
"github.com/containers/storage/pkg/idtools"
|
||||||
"github.com/cri-o/ocicni/pkg/ocicni"
|
"github.com/cri-o/ocicni/pkg/ocicni"
|
||||||
|
"github.com/opencontainers/runtime-spec/specs-go"
|
||||||
"github.com/opencontainers/runtime-tools/generate"
|
"github.com/opencontainers/runtime-tools/generate"
|
||||||
"github.com/pkg/errors"
|
"github.com/pkg/errors"
|
||||||
"github.com/sirupsen/logrus"
|
"github.com/sirupsen/logrus"
|
||||||
|
@ -559,7 +560,6 @@ func WithMaxLogSize(limit int64) CtrCreateOption {
|
||||||
if ctr.valid {
|
if ctr.valid {
|
||||||
return define.ErrRuntimeFinalized
|
return define.ErrRuntimeFinalized
|
||||||
}
|
}
|
||||||
|
|
||||||
ctr.config.LogSize = limit
|
ctr.config.LogSize = limit
|
||||||
|
|
||||||
return nil
|
return nil
|
||||||
|
@ -867,7 +867,6 @@ func WithMountNSFrom(nsCtr *Container) CtrCreateOption {
|
||||||
if err := checkDependencyContainer(nsCtr, ctr); err != nil {
|
if err := checkDependencyContainer(nsCtr, ctr); err != nil {
|
||||||
return err
|
return err
|
||||||
}
|
}
|
||||||
|
|
||||||
ctr.config.MountNsCtr = nsCtr.ID()
|
ctr.config.MountNsCtr = nsCtr.ID()
|
||||||
|
|
||||||
return nil
|
return nil
|
||||||
|
@ -2359,3 +2358,42 @@ func WithVolatile() CtrCreateOption {
|
||||||
return nil
|
return nil
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
// WithPodCPUPAQ takes the given cpu period and quota and inserts them in the proper place.
|
||||||
|
func WithPodCPUPAQ(period uint64, quota int64) PodCreateOption {
|
||||||
|
return func(pod *Pod) error {
|
||||||
|
if pod.valid {
|
||||||
|
return define.ErrPodFinalized
|
||||||
|
}
|
||||||
|
if pod.CPUPeriod() != 0 && pod.CPUQuota() != 0 {
|
||||||
|
pod.config.InfraContainer.ResourceLimits.CPU = &specs.LinuxCPU{
|
||||||
|
Period: &period,
|
||||||
|
Quota: "a,
|
||||||
|
}
|
||||||
|
} else {
|
||||||
|
pod.config.InfraContainer.ResourceLimits = &specs.LinuxResources{}
|
||||||
|
pod.config.InfraContainer.ResourceLimits.CPU = &specs.LinuxCPU{
|
||||||
|
Period: &period,
|
||||||
|
Quota: "a,
|
||||||
|
}
|
||||||
|
}
|
||||||
|
return nil
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
// WithPodCPUSetCPUS computes and sets the Cpus linux resource string which determines the amount of cores, from those available, we are allowed to execute on
|
||||||
|
func WithPodCPUSetCPUs(inp string) PodCreateOption {
|
||||||
|
return func(pod *Pod) error {
|
||||||
|
if pod.valid {
|
||||||
|
return define.ErrPodFinalized
|
||||||
|
}
|
||||||
|
if pod.ResourceLim().CPU.Period != nil {
|
||||||
|
pod.config.InfraContainer.ResourceLimits.CPU.Cpus = inp
|
||||||
|
} else {
|
||||||
|
pod.config.InfraContainer.ResourceLimits = &specs.LinuxResources{}
|
||||||
|
pod.config.InfraContainer.ResourceLimits.CPU = &specs.LinuxCPU{}
|
||||||
|
pod.config.InfraContainer.ResourceLimits.CPU.Cpus = inp
|
||||||
|
}
|
||||||
|
return nil
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
104
libpod/pod.go
104
libpod/pod.go
|
@ -1,12 +1,14 @@
|
||||||
package libpod
|
package libpod
|
||||||
|
|
||||||
import (
|
import (
|
||||||
|
"context"
|
||||||
"net"
|
"net"
|
||||||
"time"
|
"time"
|
||||||
|
|
||||||
"github.com/containers/podman/v3/libpod/define"
|
"github.com/containers/podman/v3/libpod/define"
|
||||||
"github.com/containers/podman/v3/libpod/lock"
|
"github.com/containers/podman/v3/libpod/lock"
|
||||||
"github.com/cri-o/ocicni/pkg/ocicni"
|
"github.com/cri-o/ocicni/pkg/ocicni"
|
||||||
|
"github.com/opencontainers/runtime-spec/specs-go"
|
||||||
"github.com/pkg/errors"
|
"github.com/pkg/errors"
|
||||||
)
|
)
|
||||||
|
|
||||||
|
@ -91,25 +93,26 @@ type podState struct {
|
||||||
// Generally speaking, aside from those two exceptions, these options will set
|
// Generally speaking, aside from those two exceptions, these options will set
|
||||||
// the equivalent field in the container's configuration.
|
// the equivalent field in the container's configuration.
|
||||||
type InfraContainerConfig struct {
|
type InfraContainerConfig struct {
|
||||||
ConmonPidFile string `json:"conmonPidFile"`
|
ConmonPidFile string `json:"conmonPidFile"`
|
||||||
HasInfraContainer bool `json:"makeInfraContainer"`
|
HasInfraContainer bool `json:"makeInfraContainer"`
|
||||||
NoNetwork bool `json:"noNetwork,omitempty"`
|
NoNetwork bool `json:"noNetwork,omitempty"`
|
||||||
HostNetwork bool `json:"infraHostNetwork,omitempty"`
|
HostNetwork bool `json:"infraHostNetwork,omitempty"`
|
||||||
PortBindings []ocicni.PortMapping `json:"infraPortBindings"`
|
PortBindings []ocicni.PortMapping `json:"infraPortBindings"`
|
||||||
StaticIP net.IP `json:"staticIP,omitempty"`
|
StaticIP net.IP `json:"staticIP,omitempty"`
|
||||||
StaticMAC net.HardwareAddr `json:"staticMAC,omitempty"`
|
StaticMAC net.HardwareAddr `json:"staticMAC,omitempty"`
|
||||||
UseImageResolvConf bool `json:"useImageResolvConf,omitempty"`
|
UseImageResolvConf bool `json:"useImageResolvConf,omitempty"`
|
||||||
DNSServer []string `json:"dnsServer,omitempty"`
|
DNSServer []string `json:"dnsServer,omitempty"`
|
||||||
DNSSearch []string `json:"dnsSearch,omitempty"`
|
DNSSearch []string `json:"dnsSearch,omitempty"`
|
||||||
DNSOption []string `json:"dnsOption,omitempty"`
|
DNSOption []string `json:"dnsOption,omitempty"`
|
||||||
UseImageHosts bool `json:"useImageHosts,omitempty"`
|
UseImageHosts bool `json:"useImageHosts,omitempty"`
|
||||||
HostAdd []string `json:"hostsAdd,omitempty"`
|
HostAdd []string `json:"hostsAdd,omitempty"`
|
||||||
Networks []string `json:"networks,omitempty"`
|
Networks []string `json:"networks,omitempty"`
|
||||||
ExitCommand []string `json:"exitCommand,omitempty"`
|
ExitCommand []string `json:"exitCommand,omitempty"`
|
||||||
InfraImage string `json:"infraImage,omitempty"`
|
InfraImage string `json:"infraImage,omitempty"`
|
||||||
InfraCommand []string `json:"infraCommand,omitempty"`
|
InfraCommand []string `json:"infraCommand,omitempty"`
|
||||||
Slirp4netns bool `json:"slirp4netns,omitempty"`
|
Slirp4netns bool `json:"slirp4netns,omitempty"`
|
||||||
NetworkOptions map[string][]string `json:"network_options,omitempty"`
|
NetworkOptions map[string][]string `json:"network_options,omitempty"`
|
||||||
|
ResourceLimits *specs.LinuxResources `json:"resource_limits,omitempty"`
|
||||||
}
|
}
|
||||||
|
|
||||||
// ID retrieves the pod's ID
|
// ID retrieves the pod's ID
|
||||||
|
@ -128,6 +131,45 @@ func (p *Pod) Namespace() string {
|
||||||
return p.config.Namespace
|
return p.config.Namespace
|
||||||
}
|
}
|
||||||
|
|
||||||
|
// ResourceLim returns the cpuset resource limits for the pod
|
||||||
|
func (p *Pod) ResourceLim() *specs.LinuxResources {
|
||||||
|
resCopy := &specs.LinuxResources{}
|
||||||
|
if err := JSONDeepCopy(p.config.InfraContainer.ResourceLimits, resCopy); err != nil {
|
||||||
|
return nil
|
||||||
|
}
|
||||||
|
if resCopy != nil && resCopy.CPU != nil {
|
||||||
|
return resCopy
|
||||||
|
}
|
||||||
|
empty := &specs.LinuxResources{
|
||||||
|
CPU: &specs.LinuxCPU{},
|
||||||
|
}
|
||||||
|
return empty
|
||||||
|
}
|
||||||
|
|
||||||
|
// CPUPeriod returns the pod CPU period
|
||||||
|
func (p *Pod) CPUPeriod() uint64 {
|
||||||
|
resCopy := &specs.LinuxResources{}
|
||||||
|
if err := JSONDeepCopy(p.config.InfraContainer.ResourceLimits, resCopy); err != nil {
|
||||||
|
return 0
|
||||||
|
}
|
||||||
|
if resCopy != nil && resCopy.CPU != nil && resCopy.CPU.Period != nil {
|
||||||
|
return *resCopy.CPU.Period
|
||||||
|
}
|
||||||
|
return 0
|
||||||
|
}
|
||||||
|
|
||||||
|
// CPUQuota returns the pod CPU quota
|
||||||
|
func (p *Pod) CPUQuota() int64 {
|
||||||
|
resCopy := &specs.LinuxResources{}
|
||||||
|
if err := JSONDeepCopy(p.config.InfraContainer.ResourceLimits, resCopy); err != nil {
|
||||||
|
return 0
|
||||||
|
}
|
||||||
|
if resCopy != nil && resCopy.CPU != nil && resCopy.CPU.Quota != nil {
|
||||||
|
return *resCopy.CPU.Quota
|
||||||
|
}
|
||||||
|
return 0
|
||||||
|
}
|
||||||
|
|
||||||
// Labels returns the pod's labels
|
// Labels returns the pod's labels
|
||||||
func (p *Pod) Labels() map[string]string {
|
func (p *Pod) Labels() map[string]string {
|
||||||
labels := make(map[string]string)
|
labels := make(map[string]string)
|
||||||
|
@ -208,7 +250,31 @@ func (p *Pod) CgroupPath() (string, error) {
|
||||||
if err := p.updatePod(); err != nil {
|
if err := p.updatePod(); err != nil {
|
||||||
return "", err
|
return "", err
|
||||||
}
|
}
|
||||||
|
if p.state.CgroupPath != "" {
|
||||||
|
return p.state.CgroupPath, nil
|
||||||
|
}
|
||||||
|
if !p.HasInfraContainer() {
|
||||||
|
return "", errors.Wrap(define.ErrNoSuchCtr, "pod has no infra container")
|
||||||
|
}
|
||||||
|
|
||||||
|
id := p.state.InfraContainerID
|
||||||
|
|
||||||
|
if id != "" {
|
||||||
|
ctr, err := p.runtime.state.Container(id)
|
||||||
|
if err != nil {
|
||||||
|
return "", errors.Wrapf(err, "could not get infra")
|
||||||
|
}
|
||||||
|
if ctr != nil {
|
||||||
|
ctr.Start(context.Background(), false)
|
||||||
|
cgroupPath, err := ctr.CGroupPath()
|
||||||
|
if err != nil {
|
||||||
|
return "", errors.Wrapf(err, "could not get container cgroup")
|
||||||
|
}
|
||||||
|
p.state.CgroupPath = cgroupPath
|
||||||
|
p.save()
|
||||||
|
return cgroupPath, nil
|
||||||
|
}
|
||||||
|
}
|
||||||
return p.state.CgroupPath, nil
|
return p.state.CgroupPath, nil
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
|
@ -538,6 +538,9 @@ func (p *Pod) Inspect() (*define.InspectPodData, error) {
|
||||||
infraConfig.StaticMAC = p.config.InfraContainer.StaticMAC.String()
|
infraConfig.StaticMAC = p.config.InfraContainer.StaticMAC.String()
|
||||||
infraConfig.NoManageResolvConf = p.config.InfraContainer.UseImageResolvConf
|
infraConfig.NoManageResolvConf = p.config.InfraContainer.UseImageResolvConf
|
||||||
infraConfig.NoManageHosts = p.config.InfraContainer.UseImageHosts
|
infraConfig.NoManageHosts = p.config.InfraContainer.UseImageHosts
|
||||||
|
infraConfig.CPUPeriod = p.CPUPeriod()
|
||||||
|
infraConfig.CPUQuota = p.CPUQuota()
|
||||||
|
infraConfig.CPUSetCPUs = p.ResourceLim().CPU.Cpus
|
||||||
|
|
||||||
if len(p.config.InfraContainer.DNSServer) > 0 {
|
if len(p.config.InfraContainer.DNSServer) > 0 {
|
||||||
infraConfig.DNSServer = make([]string, 0, len(p.config.InfraContainer.DNSServer))
|
infraConfig.DNSServer = make([]string, 0, len(p.config.InfraContainer.DNSServer))
|
||||||
|
@ -581,6 +584,9 @@ func (p *Pod) Inspect() (*define.InspectPodData, error) {
|
||||||
SharedNamespaces: sharesNS,
|
SharedNamespaces: sharesNS,
|
||||||
NumContainers: uint(len(containers)),
|
NumContainers: uint(len(containers)),
|
||||||
Containers: ctrs,
|
Containers: ctrs,
|
||||||
|
CPUSetCPUs: p.ResourceLim().CPU.Cpus,
|
||||||
|
CPUPeriod: p.CPUPeriod(),
|
||||||
|
CPUQuota: p.CPUQuota(),
|
||||||
}
|
}
|
||||||
|
|
||||||
return &inspectData, nil
|
return &inspectData, nil
|
||||||
|
|
|
@ -146,7 +146,6 @@ func (r *Runtime) makeInfraContainer(ctx context.Context, p *Pod, imgName, rawIm
|
||||||
options = append(options, WithExitCommand(p.config.InfraContainer.ExitCommand))
|
options = append(options, WithExitCommand(p.config.InfraContainer.ExitCommand))
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
g.SetRootReadonly(true)
|
g.SetRootReadonly(true)
|
||||||
g.SetProcessArgs(infraCtrCommand)
|
g.SetProcessArgs(infraCtrCommand)
|
||||||
|
|
||||||
|
@ -173,7 +172,6 @@ func (r *Runtime) makeInfraContainer(ctx context.Context, p *Pod, imgName, rawIm
|
||||||
// Ignore mqueue sysctls if not sharing IPC
|
// Ignore mqueue sysctls if not sharing IPC
|
||||||
if !p.config.UsePodIPC && strings.HasPrefix(sysctlKey, "fs.mqueue.") {
|
if !p.config.UsePodIPC && strings.HasPrefix(sysctlKey, "fs.mqueue.") {
|
||||||
logrus.Infof("Sysctl %s=%s ignored in containers.conf, since IPC Namespace for pod is unused", sysctlKey, sysctlVal)
|
logrus.Infof("Sysctl %s=%s ignored in containers.conf, since IPC Namespace for pod is unused", sysctlKey, sysctlVal)
|
||||||
|
|
||||||
continue
|
continue
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -188,7 +186,6 @@ func (r *Runtime) makeInfraContainer(ctx context.Context, p *Pod, imgName, rawIm
|
||||||
logrus.Infof("Sysctl %s=%s ignored in containers.conf, since UTS Namespace for pod is unused", sysctlKey, sysctlVal)
|
logrus.Infof("Sysctl %s=%s ignored in containers.conf, since UTS Namespace for pod is unused", sysctlKey, sysctlVal)
|
||||||
continue
|
continue
|
||||||
}
|
}
|
||||||
|
|
||||||
g.AddLinuxSysctl(sysctlKey, sysctlVal)
|
g.AddLinuxSysctl(sysctlKey, sysctlVal)
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -200,7 +197,11 @@ func (r *Runtime) makeInfraContainer(ctx context.Context, p *Pod, imgName, rawIm
|
||||||
if len(p.config.InfraContainer.ConmonPidFile) > 0 {
|
if len(p.config.InfraContainer.ConmonPidFile) > 0 {
|
||||||
options = append(options, WithConmonPidFile(p.config.InfraContainer.ConmonPidFile))
|
options = append(options, WithConmonPidFile(p.config.InfraContainer.ConmonPidFile))
|
||||||
}
|
}
|
||||||
|
newRes := new(spec.LinuxResources)
|
||||||
|
newRes.CPU = new(spec.LinuxCPU)
|
||||||
|
newRes.CPU = p.ResourceLim().CPU
|
||||||
|
|
||||||
|
g.Config.Linux.Resources.CPU = newRes.CPU
|
||||||
return r.newContainer(ctx, g.Config, options...)
|
return r.newContainer(ctx, g.Config, options...)
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -211,7 +212,6 @@ func (r *Runtime) createInfraContainer(ctx context.Context, p *Pod) (*Container,
|
||||||
if !r.valid {
|
if !r.valid {
|
||||||
return nil, define.ErrRuntimeStopped
|
return nil, define.ErrRuntimeStopped
|
||||||
}
|
}
|
||||||
|
|
||||||
imageName := p.config.InfraContainer.InfraImage
|
imageName := p.config.InfraContainer.InfraImage
|
||||||
if imageName == "" {
|
if imageName == "" {
|
||||||
imageName = r.config.Engine.InfraImage
|
imageName = r.config.Engine.InfraImage
|
||||||
|
|
|
@ -7,6 +7,8 @@ import (
|
||||||
|
|
||||||
"github.com/containers/podman/v3/libpod/define"
|
"github.com/containers/podman/v3/libpod/define"
|
||||||
"github.com/containers/podman/v3/pkg/specgen"
|
"github.com/containers/podman/v3/pkg/specgen"
|
||||||
|
"github.com/containers/podman/v3/pkg/util"
|
||||||
|
"github.com/opencontainers/runtime-spec/specs-go"
|
||||||
)
|
)
|
||||||
|
|
||||||
type PodKillOptions struct {
|
type PodKillOptions struct {
|
||||||
|
@ -116,13 +118,35 @@ type PodCreateOptions struct {
|
||||||
Name string
|
Name string
|
||||||
Net *NetOptions
|
Net *NetOptions
|
||||||
Share []string
|
Share []string
|
||||||
|
Cpus float64
|
||||||
|
CpusetCpus string
|
||||||
}
|
}
|
||||||
|
|
||||||
type PodCreateReport struct {
|
type PodCreateReport struct {
|
||||||
Id string //nolint
|
Id string //nolint
|
||||||
}
|
}
|
||||||
|
|
||||||
func (p PodCreateOptions) ToPodSpecGen(s *specgen.PodSpecGenerator) {
|
func (p *PodCreateOptions) CPULimits() *specs.LinuxCPU {
|
||||||
|
cpu := &specs.LinuxCPU{}
|
||||||
|
hasLimits := false
|
||||||
|
|
||||||
|
if p.Cpus != 0 {
|
||||||
|
period, quota := util.CoresToPeriodAndQuota(p.Cpus)
|
||||||
|
cpu.Period = &period
|
||||||
|
cpu.Quota = "a
|
||||||
|
hasLimits = true
|
||||||
|
}
|
||||||
|
if p.CpusetCpus != "" {
|
||||||
|
cpu.Cpus = p.CpusetCpus
|
||||||
|
hasLimits = true
|
||||||
|
}
|
||||||
|
if !hasLimits {
|
||||||
|
return cpu
|
||||||
|
}
|
||||||
|
return cpu
|
||||||
|
}
|
||||||
|
|
||||||
|
func (p *PodCreateOptions) ToPodSpecGen(s *specgen.PodSpecGenerator) error {
|
||||||
// Basic Config
|
// Basic Config
|
||||||
s.Name = p.Name
|
s.Name = p.Name
|
||||||
s.Hostname = p.Hostname
|
s.Hostname = p.Hostname
|
||||||
|
@ -156,6 +180,21 @@ func (p PodCreateOptions) ToPodSpecGen(s *specgen.PodSpecGenerator) {
|
||||||
|
|
||||||
// Cgroup
|
// Cgroup
|
||||||
s.CgroupParent = p.CGroupParent
|
s.CgroupParent = p.CGroupParent
|
||||||
|
|
||||||
|
// Resource config
|
||||||
|
cpuDat := p.CPULimits()
|
||||||
|
if s.ResourceLimits == nil {
|
||||||
|
s.ResourceLimits = &specs.LinuxResources{}
|
||||||
|
s.ResourceLimits.CPU = &specs.LinuxCPU{}
|
||||||
|
}
|
||||||
|
if cpuDat != nil {
|
||||||
|
s.ResourceLimits.CPU = cpuDat
|
||||||
|
if p.Cpus != 0 {
|
||||||
|
s.CPUPeriod = *cpuDat.Period
|
||||||
|
s.CPUQuota = *cpuDat.Quota
|
||||||
|
}
|
||||||
|
}
|
||||||
|
return nil
|
||||||
}
|
}
|
||||||
|
|
||||||
type PodPruneOptions struct {
|
type PodPruneOptions struct {
|
||||||
|
|
|
@ -347,7 +347,6 @@ func createContainerOptions(ctx context.Context, rt *libpod.Runtime, s *specgen.
|
||||||
options = append(options, libpod.WithLogDriver(s.LogConfiguration.Driver))
|
options = append(options, libpod.WithLogDriver(s.LogConfiguration.Driver))
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
// Security options
|
// Security options
|
||||||
if len(s.SelinuxOpts) > 0 {
|
if len(s.SelinuxOpts) > 0 {
|
||||||
options = append(options, libpod.WithSecLabels(s.SelinuxOpts))
|
options = append(options, libpod.WithSecLabels(s.SelinuxOpts))
|
||||||
|
|
|
@ -54,6 +54,14 @@ func createPodOptions(p *specgen.PodSpecGenerator, rt *libpod.Runtime) ([]libpod
|
||||||
if len(p.Name) > 0 {
|
if len(p.Name) > 0 {
|
||||||
options = append(options, libpod.WithPodName(p.Name))
|
options = append(options, libpod.WithPodName(p.Name))
|
||||||
}
|
}
|
||||||
|
if p.ResourceLimits != nil && p.ResourceLimits.CPU != nil && p.ResourceLimits.CPU.Period != nil && p.ResourceLimits.CPU.Quota != nil {
|
||||||
|
if *p.ResourceLimits.CPU.Period != 0 || *p.ResourceLimits.CPU.Quota != 0 {
|
||||||
|
options = append(options, libpod.WithPodCPUPAQ((*p.ResourceLimits.CPU.Period), (*p.ResourceLimits.CPU.Quota)))
|
||||||
|
}
|
||||||
|
}
|
||||||
|
if p.ResourceLimits != nil && p.ResourceLimits.CPU != nil && p.ResourceLimits.CPU.Cpus != "" {
|
||||||
|
options = append(options, libpod.WithPodCPUSetCPUs(p.ResourceLimits.CPU.Cpus))
|
||||||
|
}
|
||||||
if len(p.Hostname) > 0 {
|
if len(p.Hostname) > 0 {
|
||||||
options = append(options, libpod.WithPodHostname(p.Hostname))
|
options = append(options, libpod.WithPodHostname(p.Hostname))
|
||||||
}
|
}
|
||||||
|
|
|
@ -2,6 +2,8 @@ package specgen
|
||||||
|
|
||||||
import (
|
import (
|
||||||
"net"
|
"net"
|
||||||
|
|
||||||
|
spec "github.com/opencontainers/runtime-spec/specs-go"
|
||||||
)
|
)
|
||||||
|
|
||||||
// PodBasicConfig contains basic configuration options for pods.
|
// PodBasicConfig contains basic configuration options for pods.
|
||||||
|
@ -155,6 +157,16 @@ type PodSpecGenerator struct {
|
||||||
PodBasicConfig
|
PodBasicConfig
|
||||||
PodNetworkConfig
|
PodNetworkConfig
|
||||||
PodCgroupConfig
|
PodCgroupConfig
|
||||||
|
PodResourceConfig
|
||||||
|
}
|
||||||
|
|
||||||
|
type PodResourceConfig struct {
|
||||||
|
// ResourceLimits contains linux specific CPU data for the pod
|
||||||
|
ResourceLimits *spec.LinuxResources `json:"resource_limits,omitempty"`
|
||||||
|
// CPU period of the cpuset, determined by --cpus
|
||||||
|
CPUPeriod uint64 `json:"cpu_period,omitempty"`
|
||||||
|
// CPU quota of the cpuset, determined by --cpus
|
||||||
|
CPUQuota int64 `json:"cpu_quota,omitempty"`
|
||||||
}
|
}
|
||||||
|
|
||||||
// NewPodSpecGenerator creates a new pod spec
|
// NewPodSpecGenerator creates a new pod spec
|
||||||
|
|
|
@ -470,6 +470,10 @@ type ContainerResourceConfig struct {
|
||||||
// that are used to configure cgroup v2.
|
// that are used to configure cgroup v2.
|
||||||
// Optional.
|
// Optional.
|
||||||
CgroupConf map[string]string `json:"unified,omitempty"`
|
CgroupConf map[string]string `json:"unified,omitempty"`
|
||||||
|
// CPU period of the cpuset, determined by --cpus
|
||||||
|
CPUPeriod uint64 `json:"cpu_period,omitempty"`
|
||||||
|
// CPU quota of the cpuset, determined by --cpus
|
||||||
|
CPUQuota int64 `json:"cpu_quota,omitempty"`
|
||||||
}
|
}
|
||||||
|
|
||||||
// ContainerHealthCheckConfig describes a container healthcheck with attributes
|
// ContainerHealthCheckConfig describes a container healthcheck with attributes
|
||||||
|
|
|
@ -5,9 +5,12 @@ import (
|
||||||
"io/ioutil"
|
"io/ioutil"
|
||||||
"os"
|
"os"
|
||||||
"path/filepath"
|
"path/filepath"
|
||||||
|
"strconv"
|
||||||
"strings"
|
"strings"
|
||||||
|
|
||||||
|
"github.com/containers/common/pkg/sysinfo"
|
||||||
"github.com/containers/podman/v3/pkg/rootless"
|
"github.com/containers/podman/v3/pkg/rootless"
|
||||||
|
"github.com/containers/podman/v3/pkg/util"
|
||||||
. "github.com/containers/podman/v3/test/utils"
|
. "github.com/containers/podman/v3/test/utils"
|
||||||
. "github.com/onsi/ginkgo"
|
. "github.com/onsi/ginkgo"
|
||||||
. "github.com/onsi/gomega"
|
. "github.com/onsi/gomega"
|
||||||
|
@ -515,4 +518,45 @@ ENTRYPOINT ["sleep","99999"]
|
||||||
Expect(create.ExitCode()).To(BeZero())
|
Expect(create.ExitCode()).To(BeZero())
|
||||||
})
|
})
|
||||||
|
|
||||||
|
It("podman pod create --cpus", func() {
|
||||||
|
podName := "testPod"
|
||||||
|
numCPU := float64(sysinfo.NumCPU())
|
||||||
|
period, quota := util.CoresToPeriodAndQuota(numCPU)
|
||||||
|
numCPUStr := strconv.Itoa(int(numCPU))
|
||||||
|
podCreate := podmanTest.Podman([]string{"pod", "create", "--cpus", numCPUStr, "--name", podName})
|
||||||
|
podCreate.WaitWithDefaultTimeout()
|
||||||
|
Expect(podCreate.ExitCode()).To(Equal(0))
|
||||||
|
|
||||||
|
contCreate := podmanTest.Podman([]string{"container", "create", "--pod", podName, "alpine"})
|
||||||
|
contCreate.WaitWithDefaultTimeout()
|
||||||
|
Expect(podCreate.ExitCode()).To(Equal(0))
|
||||||
|
|
||||||
|
podInspect := podmanTest.Podman([]string{"pod", "inspect", podName})
|
||||||
|
podInspect.WaitWithDefaultTimeout()
|
||||||
|
Expect(podInspect.ExitCode()).To(Equal(0))
|
||||||
|
podJSON := podInspect.InspectPodToJSON()
|
||||||
|
Expect(podJSON.CPUPeriod).To(Equal(period))
|
||||||
|
Expect(podJSON.CPUQuota).To(Equal(quota))
|
||||||
|
})
|
||||||
|
|
||||||
|
It("podman pod create --cpuset-cpus", func() {
|
||||||
|
podName := "testPod"
|
||||||
|
ctrName := "testCtr"
|
||||||
|
numCPU := float64(sysinfo.NumCPU())
|
||||||
|
numCPUStr := strconv.Itoa(int(numCPU))
|
||||||
|
in := "0-" + numCPUStr
|
||||||
|
podCreate := podmanTest.Podman([]string{"pod", "create", "--cpuset-cpus", in, "--name", podName})
|
||||||
|
podCreate.WaitWithDefaultTimeout()
|
||||||
|
Expect(podCreate.ExitCode()).To(Equal(0))
|
||||||
|
|
||||||
|
contCreate := podmanTest.Podman([]string{"container", "create", "--name", ctrName, "--pod", podName, "alpine"})
|
||||||
|
contCreate.WaitWithDefaultTimeout()
|
||||||
|
Expect(podCreate.ExitCode()).To(Equal(0))
|
||||||
|
|
||||||
|
podInspect := podmanTest.Podman([]string{"pod", "inspect", podName})
|
||||||
|
podInspect.WaitWithDefaultTimeout()
|
||||||
|
Expect(podInspect.ExitCode()).To(Equal(0))
|
||||||
|
podJSON := podInspect.InspectPodToJSON()
|
||||||
|
Expect(podJSON.CPUSetCPUs).To(Equal(in))
|
||||||
|
})
|
||||||
})
|
})
|
||||||
|
|
Loading…
Reference in a new issue