Skip to content

Commit

Permalink
feat: support overriding base OCI spec for CRI
Browse files Browse the repository at this point in the history
Fixes #9827

Signed-off-by: Andrey Smirnov <andrey.smirnov@siderolabs.com>
  • Loading branch information
smira committed Nov 29, 2024
1 parent 347b758 commit e33d2f5
Show file tree
Hide file tree
Showing 21 changed files with 538 additions and 8 deletions.
4 changes: 2 additions & 2 deletions Dockerfile
Original file line number Diff line number Diff line change
Expand Up @@ -735,7 +735,7 @@ COPY --chmod=0644 hack/udevd/90-selinux.rules /rootfs/usr/lib/udev/rules.d/
COPY --chmod=0644 hack/lvm.conf /rootfs/etc/lvm/lvm.conf
RUN <<END
ln -s /usr/share/zoneinfo/Etc/UTC /rootfs/etc/localtime
touch /rootfs/etc/{extensions.yaml,resolv.conf,hosts,os-release,machine-id,cri/conf.d/cri.toml,cri/conf.d/01-registries.part,cri/conf.d/20-customization.part,ssl/certs/ca-certificates}
touch /rootfs/etc/{extensions.yaml,resolv.conf,hosts,os-release,machine-id,cri/conf.d/cri.toml,cri/conf.d/01-registries.part,cri/conf.d/20-customization.part,cri/conf.d/base-spec.json,ssl/certs/ca-certificates}
ln -s ca-certificates /rootfs/etc/ssl/certs/ca-certificates.crt
ln -s /etc/ssl /rootfs/etc/pki
ln -s /etc/ssl /rootfs/usr/share/ca-certificates
Expand Down Expand Up @@ -809,7 +809,7 @@ COPY --chmod=0644 hack/udevd/90-selinux.rules /rootfs/usr/lib/udev/rules.d/
COPY --chmod=0644 hack/lvm.conf /rootfs/etc/lvm/lvm.conf
RUN <<END
ln -s /usr/share/zoneinfo/Etc/UTC /rootfs/etc/localtime
touch /rootfs/etc/{extensions.yaml,resolv.conf,hosts,os-release,machine-id,cri/conf.d/cri.toml,cri/conf.d/01-registries.part,cri/conf.d/20-customization.part,ssl/certs/ca-certificates}
touch /rootfs/etc/{extensions.yaml,resolv.conf,hosts,os-release,machine-id,cri/conf.d/cri.toml,cri/conf.d/01-registries.part,cri/conf.d/20-customization.part,cri/conf.d/base-spec.json,ssl/certs/ca-certificates}
ln -s /etc/ssl /rootfs/etc/pki
ln -s ca-certificates /rootfs/etc/ssl/certs/ca-certificates.crt
ln -s /etc/ssl /rootfs/usr/share/ca-certificates
Expand Down
3 changes: 3 additions & 0 deletions hack/cri-plugin.part
Original file line number Diff line number Diff line change
Expand Up @@ -2,3 +2,6 @@ version = 3

[plugins."io.containerd.cri.v1.images"]
discard_unpacked_layers = true

[plugins."io.containerd.cri.v1.runtime".containerd.runtimes.runc]
base_runtime_spec = "/etc/cri/conf.d/base-spec.json"
6 changes: 6 additions & 0 deletions hack/release.toml
Original file line number Diff line number Diff line change
Expand Up @@ -126,6 +126,12 @@ The command `talosctl disks` was removed, please use `talosctl get disks`, `talo
title = "talosctl wipe"
description = """\
The new command `talosctl wipe disk` allows to wipe a disk or a partition which is not used as a volume.
"""

[notes.oci-base-spec]
title = "OCI Base Runtime Spec"
description = """\
Talos now allows to [modify the OCI base runtime spec for the container runtime](https://www.talos.dev/v1.9/advanced/oci-base-spec/).
"""

[make_deps]
Expand Down
137 changes: 137 additions & 0 deletions internal/app/machined/pkg/controllers/files/cri_base_runtime_spec.go
Original file line number Diff line number Diff line change
@@ -0,0 +1,137 @@
// This Source Code Form is subject to the terms of the Mozilla Public
// License, v. 2.0. If a copy of the MPL was not distributed with this
// file, You can obtain one at http://mozilla.org/MPL/2.0/.

package files

import (
"context"
"encoding/json"
"fmt"

"github.com/containerd/containerd/v2/core/containers"
"github.com/containerd/containerd/v2/pkg/namespaces"
"github.com/containerd/containerd/v2/pkg/oci"
"github.com/containerd/platforms"
"github.com/cosi-project/runtime/pkg/controller"
"github.com/cosi-project/runtime/pkg/safe"
"github.com/cosi-project/runtime/pkg/state"
"github.com/siderolabs/gen/optional"
"go.uber.org/zap"

"github.com/siderolabs/talos/pkg/machinery/config/merge"
"github.com/siderolabs/talos/pkg/machinery/constants"
"github.com/siderolabs/talos/pkg/machinery/resources/config"
"github.com/siderolabs/talos/pkg/machinery/resources/files"
)

// CRIBaseRuntimeSpecController generates parts of the CRI config for base OCI runtime configuration.
type CRIBaseRuntimeSpecController struct{}

// Name implements controller.Controller interface.
func (ctrl *CRIBaseRuntimeSpecController) Name() string {
return "files.CRIBaseRuntimeSpecController"
}

// Inputs implements controller.Controller interface.
func (ctrl *CRIBaseRuntimeSpecController) Inputs() []controller.Input {
return []controller.Input{
{
Namespace: config.NamespaceName,
Type: config.MachineConfigType,
ID: optional.Some(config.V1Alpha1ID),
Kind: controller.InputWeak,
},
}
}

// Outputs implements controller.Controller interface.
func (ctrl *CRIBaseRuntimeSpecController) Outputs() []controller.Output {
return []controller.Output{
{
Type: files.EtcFileSpecType,
Kind: controller.OutputShared,
},
}
}

// Run implements controller.Controller interface.
//
//nolint:gocyclo
func (ctrl *CRIBaseRuntimeSpecController) Run(ctx context.Context, r controller.Runtime, _ *zap.Logger) error {
for {
select {
case <-ctx.Done():
return nil
case <-r.EventCh():
}

cfg, err := safe.ReaderGetByID[*config.MachineConfig](ctx, r, config.V1Alpha1ID)
if err != nil {
if state.IsNotFoundError(err) {
// wait for machine config to be available
continue
}

return fmt.Errorf("error getting machine config: %w", err)
}

if cfg.Config().Machine() == nil {
// wait for machine config to be available
continue
}

platform := platforms.DefaultString()

defaultSpec, err := oci.GenerateSpecWithPlatform(
namespaces.WithNamespace(ctx, constants.K8sContainerdNamespace),
nil,
platform,
&containers.Container{},
)
if err != nil {
return fmt.Errorf("error generating default spec: %w", err)
}

// compatibility with CRI defaults:
// * remove default rlimits (See https://github.com/containerd/cri/issues/515)
defaultSpec.Process.Rlimits = nil

if len(cfg.Config().Machine().BaseRuntimeSpecOverrides()) > 0 {
var overrides oci.Spec

jsonOverrides, err := json.Marshal(cfg.Config().Machine().BaseRuntimeSpecOverrides())
if err != nil {
return fmt.Errorf("error marshaling runtime spec overrides: %w", err)
}

if err := json.Unmarshal(jsonOverrides, &overrides); err != nil {
return fmt.Errorf("error unmarshaling runtime spec overrides: %w", err)
}

if err := merge.Merge(defaultSpec, &overrides); err != nil {
return fmt.Errorf("error merging runtime spec overrides: %w", err)
}
}

contents, err := json.Marshal(defaultSpec)
if err != nil {
return fmt.Errorf("error marshaling runtime spec: %w", err)
}

if err := safe.WriterModify(ctx, r, files.NewEtcFileSpec(files.NamespaceName, constants.CRIBaseRuntimeSpec),
func(r *files.EtcFileSpec) error {
spec := r.TypedSpec()

spec.Contents = contents
spec.Mode = 0o600
spec.SelinuxLabel = constants.EtcSelinuxLabel

return nil
}); err != nil {
return fmt.Errorf("error modifying resource: %w", err)
}

r.ResetRestartBackoff()
}
}
Original file line number Diff line number Diff line change
@@ -0,0 +1,106 @@
// This Source Code Form is subject to the terms of the Mozilla Public
// License, v. 2.0. If a copy of the MPL was not distributed with this
// file, You can obtain one at http://mozilla.org/MPL/2.0/.

package files_test

import (
"encoding/json"
"testing"
"time"

"github.com/containerd/containerd/v2/pkg/oci"
"github.com/stretchr/testify/assert"
"github.com/stretchr/testify/suite"

"github.com/siderolabs/talos/internal/app/machined/pkg/controllers/ctest"
filesctrl "github.com/siderolabs/talos/internal/app/machined/pkg/controllers/files"
"github.com/siderolabs/talos/pkg/machinery/config/container"
"github.com/siderolabs/talos/pkg/machinery/config/types/v1alpha1"
"github.com/siderolabs/talos/pkg/machinery/constants"
"github.com/siderolabs/talos/pkg/machinery/resources/config"
"github.com/siderolabs/talos/pkg/machinery/resources/files"
)

type CRIBaseRuntimeSpecSuite struct {
ctest.DefaultSuite
}

func (suite *CRIBaseRuntimeSpecSuite) TestDefaults() {
cfg := config.NewMachineConfig(
container.NewV1Alpha1(
&v1alpha1.Config{
ConfigVersion: "v1alpha1",
MachineConfig: &v1alpha1.MachineConfig{
MachineType: "controlplane",
},
},
),
)

suite.Require().NoError(suite.State().Create(suite.Ctx(), cfg))

ctest.AssertResource(suite, constants.CRIBaseRuntimeSpec, func(etcFile *files.EtcFileSpec, asrt *assert.Assertions) {
contents := etcFile.TypedSpec().Contents

var ociSpec oci.Spec

asrt.NoError(json.Unmarshal(contents, &ociSpec))

asrt.Empty(ociSpec.Process.Rlimits)
})
}

func (suite *CRIBaseRuntimeSpecSuite) TestOverrides() {
cfg := config.NewMachineConfig(
container.NewV1Alpha1(
&v1alpha1.Config{
ConfigVersion: "v1alpha1",
MachineConfig: &v1alpha1.MachineConfig{
MachineType: "controlplane",
MachineBaseRuntimeSpecOverrides: v1alpha1.Unstructured{
Object: map[string]any{
"process": map[string]any{
"rlimits": []map[string]any{
{
"type": "RLIMIT_NOFILE",
"hard": 1024,
"soft": 1024,
},
},
},
},
},
},
},
),
)

suite.Require().NoError(suite.State().Create(suite.Ctx(), cfg))

ctest.AssertResource(suite, constants.CRIBaseRuntimeSpec, func(etcFile *files.EtcFileSpec, asrt *assert.Assertions) {
contents := etcFile.TypedSpec().Contents

var ociSpec oci.Spec

asrt.NoError(json.Unmarshal(contents, &ociSpec))

asrt.NotEmpty(ociSpec.Process.Rlimits)
asrt.Equal("RLIMIT_NOFILE", ociSpec.Process.Rlimits[0].Type)
asrt.Equal(uint64(1024), ociSpec.Process.Rlimits[0].Hard)
asrt.Equal(uint64(1024), ociSpec.Process.Rlimits[0].Soft)
})
}

func TestCRIBaseRuntimeSpecSuite(t *testing.T) {
t.Parallel()

suite.Run(t, &CRIBaseRuntimeSpecSuite{
DefaultSuite: ctest.DefaultSuite{
Timeout: 10 * time.Second,
AfterSetup: func(suite *ctest.DefaultSuite) {
suite.Require().NoError(suite.Runtime().RegisterController(&filesctrl.CRIBaseRuntimeSpecController{}))
},
},
})
}
Original file line number Diff line number Diff line change
Expand Up @@ -145,6 +145,7 @@ func (ctrl *Controller) Run(ctx context.Context, drainer *runtime.Drainer) error
&etcd.PKIController{},
&etcd.SpecController{},
&etcd.MemberController{},
&files.CRIBaseRuntimeSpecController{},
&files.CRIConfigPartsController{},
&files.CRIRegistryConfigController{},
&files.EtcFileController{
Expand Down
Loading

0 comments on commit e33d2f5

Please sign in to comment.