Blob Blame History Raw
From bdf3fc2b4bfea5ee3f91c5c2758c5154f95d27ad Mon Sep 17 00:00:00 2001
From: Kazuyoshi Kato <katokazu@amazon.com>
Date: Tue, 22 Mar 2022 00:40:39 +0000
Subject: [PATCH] Use typeurl.Any instead of github.com/gogo/protobuf/types.Any

This commit upgrades github.com/containerd/typeurl to use typeurl.Any.
The interface hides gogo/protobuf/types.Any from containerd's Go client.

Signed-off-by: Kazuyoshi Kato <katokazu@amazon.com>
---
 cmd/containerd-shim/main_unix.go              |  4 +-
 cmd/ctr/commands/containers/containers.go     |  2 +-
 cmd/ctr/commands/tasks/kill.go                | 29 ++++++
 container.go                                  | 10 +-
 container_checkpoint_opts.go                  |  9 +-
 container_opts.go                             | 10 +-
 containers/containers.go                      |  8 +-
 containerstore.go                             | 19 +++-
 events.go                                     |  5 +-
 events/events.go                              |  3 +-
 events/exchange/exchange.go                   |  8 +-
 go.mod                                        |  2 +-
 go.sum                                        |  3 +-
 integration/client/container_test.go          |  8 +-
 integration/client/go.mod                     |  2 +-
 integration/client/go.sum                     |  3 +-
 metadata/boltutil/helpers.go                  | 20 ++--
 metadata/containers.go                        |  3 +-
 metadata/containers_test.go                   | 83 ++++++++++-------
 pkg/cri/server/events.go                      |  3 +-
 pkg/cri/server/helpers.go                     |  5 +-
 pkg/cri/server/helpers_test.go                | 13 +++
 pkg/cri/server/restart.go                     |  4 +-
 protobuf/any.go                               | 47 ++++++++++
 protobuf/any_test.go                          | 26 ++++++
 runtime/runtime.go                            |  8 +-
 runtime/v1/linux/runtime.go                   |  9 +-
 runtime/v1/linux/task.go                      |  4 +-
 runtime/v1/shim/service.go                    |  3 +-
 runtime/v2/manager.go                         |  7 +-
 runtime/v2/runc/container.go                  |  6 +-
 runtime/v2/runc/task/service.go               |  5 +-
 runtime/v2/runc/v1/service.go                 |  5 +-
 runtime/v2/shim.go                            |  5 +-
 runtime/v2/shim/publisher.go                  |  4 +-
 services/containers/helpers.go                | 20 +++-
 services/events/service.go                    |  3 +-
 services/tasks/local.go                       |  5 +-
 task.go                                       |  7 +-
 42 files changed, 365 insertions(+), 150 deletions(-)
 create mode 100644 protobuf/any.go
 create mode 100644 protobuf/any_test.go

diff --git a/cmd/containerd-shim/main_unix.go b/cmd/containerd-shim/main_unix.go
index 024611bf3..ef32ae38b 100644
--- a/cmd/containerd-shim/main_unix.go
+++ b/cmd/containerd-shim/main_unix.go
@@ -38,12 +38,12 @@ import (
 	"github.com/containerd/containerd/events"
 	"github.com/containerd/containerd/namespaces"
 	"github.com/containerd/containerd/pkg/process"
+	"github.com/containerd/containerd/protobuf"
 	shimlog "github.com/containerd/containerd/runtime/v1"
 	"github.com/containerd/containerd/runtime/v1/shim"
 	shimapi "github.com/containerd/containerd/runtime/v1/shim/v1"
 	"github.com/containerd/containerd/sys/reaper"
 	"github.com/containerd/ttrpc"
-	"github.com/containerd/typeurl"
 	ptypes "github.com/gogo/protobuf/types"
 	"github.com/sirupsen/logrus"
 	exec "golang.org/x/sys/execabs"
@@ -286,7 +286,7 @@ type remoteEventsPublisher struct {
 
 func (l *remoteEventsPublisher) Publish(ctx context.Context, topic string, event events.Event) error {
 	ns, _ := namespaces.Namespace(ctx)
-	encoded, err := typeurl.MarshalAny(event)
+	encoded, err := protobuf.MarshalAnyToProto(event)
 	if err != nil {
 		return err
 	}
diff --git a/cmd/ctr/commands/containers/containers.go b/cmd/ctr/commands/containers/containers.go
index d1025344e..3f2d55d6c 100644
--- a/cmd/ctr/commands/containers/containers.go
+++ b/cmd/ctr/commands/containers/containers.go
@@ -280,7 +280,7 @@ var infoCommand = cli.Command{
 			return nil
 		}
 
-		if info.Spec != nil && info.Spec.Value != nil {
+		if info.Spec != nil && info.Spec.GetValue() != nil {
 			v, err := typeurl.UnmarshalAny(info.Spec)
 			if err != nil {
 				return err
diff --git a/container.go b/container.go
index 7d8d674c8..4236fecd2 100644
--- a/container.go
+++ b/container.go
@@ -32,10 +32,10 @@ import (
 	"github.com/containerd/containerd/errdefs"
 	"github.com/containerd/containerd/images"
 	"github.com/containerd/containerd/oci"
+	"github.com/containerd/containerd/protobuf"
 	"github.com/containerd/containerd/runtime/v2/runc/options"
 	"github.com/containerd/fifo"
 	"github.com/containerd/typeurl"
-	prototypes "github.com/gogo/protobuf/types"
 	ver "github.com/opencontainers/image-spec/specs-go"
 	ocispec "github.com/opencontainers/image-spec/specs-go/v1"
 	"github.com/opencontainers/selinux/go-selinux/label"
@@ -74,7 +74,7 @@ type Container interface {
 	// SetLabels sets the provided labels for the container and returns the final label set
 	SetLabels(context.Context, map[string]string) (map[string]string, error)
 	// Extensions returns the extensions set on the container
-	Extensions(context.Context) (map[string]prototypes.Any, error)
+	Extensions(context.Context) (map[string]typeurl.Any, error)
 	// Update a container
 	Update(context.Context, ...UpdateContainerOpts) error
 	// Checkpoint creates a checkpoint image of the current container
@@ -120,7 +120,7 @@ func (c *container) Info(ctx context.Context, opts ...InfoOpts) (containers.Cont
 	return c.metadata, nil
 }
 
-func (c *container) Extensions(ctx context.Context) (map[string]prototypes.Any, error) {
+func (c *container) Extensions(ctx context.Context) (map[string]typeurl.Any, error) {
 	r, err := c.get(ctx)
 	if err != nil {
 		return nil, err
@@ -163,7 +163,7 @@ func (c *container) Spec(ctx context.Context) (*oci.Spec, error) {
 		return nil, err
 	}
 	var s oci.Spec
-	if err := json.Unmarshal(r.Spec.Value, &s); err != nil {
+	if err := json.Unmarshal(r.Spec.GetValue(), &s); err != nil {
 		return nil, err
 	}
 	return &s, nil
@@ -284,7 +284,7 @@ func (c *container) NewTask(ctx context.Context, ioCreate cio.Creator, opts ...N
 		if err != nil {
 			return nil, err
 		}
-		request.Options = any
+		request.Options = protobuf.FromAny(any)
 	}
 	t := &task{
 		client: c.client,
diff --git a/container_checkpoint_opts.go b/container_checkpoint_opts.go
index a64ef618b..c39628535 100644
--- a/container_checkpoint_opts.go
+++ b/container_checkpoint_opts.go
@@ -28,9 +28,9 @@ import (
 	"github.com/containerd/containerd/diff"
 	"github.com/containerd/containerd/images"
 	"github.com/containerd/containerd/platforms"
+	"github.com/containerd/containerd/protobuf"
 	"github.com/containerd/containerd/rootfs"
 	"github.com/containerd/containerd/runtime/v2/runc/options"
-	"github.com/containerd/typeurl"
 	imagespec "github.com/opencontainers/image-spec/specs-go/v1"
 )
 
@@ -56,7 +57,7 @@ func WithCheckpointImage(ctx context.Context, client *Client, c *containers.Cont
 
 // WithCheckpointTask includes the running task
 func WithCheckpointTask(ctx context.Context, client *Client, c *containers.Container, index *imagespec.Index, copts *options.CheckpointOptions) error {
-	any, err := typeurl.MarshalAny(copts)
+	any, err := protobuf.MarshalAnyToProto(copts)
 	if err != nil {
 		return nil
 	}
@@ -97,8 +98,8 @@ func WithCheckpointTask(ctx context.Context, client *Client, c *containers.Conta
 
 // WithCheckpointRuntime includes the container runtime info
 func WithCheckpointRuntime(ctx context.Context, client *Client, c *containers.Container, index *imagespec.Index, copts *options.CheckpointOptions) error {
-	if c.Runtime.Options != nil {
-		data, err := c.Runtime.Options.Marshal()
+	if c.Runtime.Options != nil && c.Runtime.Options.GetValue() != nil {
+		data, err := protobuf.FromAny(c.Runtime.Options).Marshal()
 		if err != nil {
 			return err
 		}
diff --git a/container_opts.go b/container_opts.go
index 4d630ea6c..f005fe1c7 100644
--- a/container_opts.go
+++ b/container_opts.go
@@ -27,9 +27,9 @@ import (
 	"github.com/containerd/containerd/errdefs"
 	"github.com/containerd/containerd/images"
 	"github.com/containerd/containerd/oci"
+	"github.com/containerd/containerd/protobuf"
 	"github.com/containerd/containerd/snapshots"
 	"github.com/containerd/typeurl"
-	"github.com/gogo/protobuf/types"
 	"github.com/opencontainers/image-spec/identity"
 	v1 "github.com/opencontainers/image-spec/specs-go/v1"
 )
@@ -57,7 +57,7 @@ type InfoConfig struct {
 func WithRuntime(name string, options interface{}) NewContainerOpts {
 	return func(ctx context.Context, client *Client, c *containers.Container) error {
 		var (
-			any *types.Any
+			any typeurl.Any
 			err error
 		)
 		if options != nil {
@@ -288,9 +288,9 @@ func WithContainerExtension(name string, extension interface{}) NewContainerOpts
 		}
 
 		if c.Extensions == nil {
-			c.Extensions = make(map[string]types.Any)
+			c.Extensions = make(map[string]typeurl.Any)
 		}
-		c.Extensions[name] = *any
+		c.Extensions[name] = any
 		return nil
 	}
 }
@@ -315,7 +315,7 @@ func WithSpec(s *oci.Spec, opts ...oci.SpecOpts) NewContainerOpts {
 		}
 
 		var err error
-		c.Spec, err = typeurl.MarshalAny(s)
+		c.Spec, err = protobuf.MarshalAnyToProto(s)
 		return err
 	}
 }
diff --git a/containers/containers.go b/containers/containers.go
index 7174bbd6a..275f8069e 100644
--- a/containers/containers.go
+++ b/containers/containers.go
@@ -20,7 +20,7 @@ import (
 	"context"
 	"time"
 
-	"github.com/gogo/protobuf/types"
+	"github.com/containerd/typeurl"
 )
 
 // Container represents the set of data pinned by a container. Unless otherwise
@@ -53,7 +53,7 @@ type Container struct {
 	// container.
 	//
 	// This field is required but mutable.
-	Spec *types.Any
+	Spec typeurl.Any
 
 	// SnapshotKey specifies the snapshot key to use for the container's root
 	// filesystem. When starting a task from this container, a caller should
@@ -75,13 +75,13 @@ type Container struct {
 	UpdatedAt time.Time
 
 	// Extensions stores client-specified metadata
-	Extensions map[string]types.Any
+	Extensions map[string]typeurl.Any
 }
 
 // RuntimeInfo holds runtime specific information
 type RuntimeInfo struct {
 	Name    string
-	Options *types.Any
+	Options typeurl.Any
 }
 
 // Store interacts with the underlying container storage
diff --git a/containerstore.go b/containerstore.go
index 2756e2a68..456e3e52a 100644
--- a/containerstore.go
+++ b/containerstore.go
@@ -24,6 +24,8 @@ import (
 	containersapi "github.com/containerd/containerd/api/services/containers/v1"
 	"github.com/containerd/containerd/containers"
 	"github.com/containerd/containerd/errdefs"
+	"github.com/containerd/containerd/protobuf"
+	"github.com/containerd/typeurl"
 	ptypes "github.com/gogo/protobuf/types"
 	"google.golang.org/grpc/codes"
 	"google.golang.org/grpc/status"
@@ -148,18 +150,22 @@ func (r *remoteContainers) Delete(ctx context.Context, id string) error {
 }
 
 func containerToProto(container *containers.Container) containersapi.Container {
+	extensions := make(map[string]ptypes.Any)
+	for k, v := range container.Extensions {
+		extensions[k] = *protobuf.FromAny(v)
+	}
 	return containersapi.Container{
 		ID:     container.ID,
 		Labels: container.Labels,
 		Image:  container.Image,
 		Runtime: &containersapi.Container_Runtime{
 			Name:    container.Runtime.Name,
-			Options: container.Runtime.Options,
+			Options: protobuf.FromAny(container.Runtime.Options),
 		},
-		Spec:        container.Spec,
+		Spec:        protobuf.FromAny(container.Spec),
 		Snapshotter: container.Snapshotter,
 		SnapshotKey: container.SnapshotKey,
-		Extensions:  container.Extensions,
+		Extensions:  extensions,
 	}
 }
 
@@ -171,6 +177,11 @@ func containerFromProto(containerpb *containersapi.Container) containers.Contain
 			Options: containerpb.Runtime.Options,
 		}
 	}
+	extensions := make(map[string]typeurl.Any)
+	for k, v := range containerpb.Extensions {
+		v := v
+		extensions[k] = &v
+	}
 	return containers.Container{
 		ID:          containerpb.ID,
 		Labels:      containerpb.Labels,
@@ -181,7 +192,7 @@ func containerFromProto(containerpb *containersapi.Container) containers.Contain
 		SnapshotKey: containerpb.SnapshotKey,
 		CreatedAt:   containerpb.CreatedAt,
 		UpdatedAt:   containerpb.UpdatedAt,
-		Extensions:  containerpb.Extensions,
+		Extensions:  extensions,
 	}
 }
 
diff --git a/events.go b/events.go
index 3577b7c3a..d6499ad3b 100644
--- a/events.go
+++ b/events.go
@@ -22,6 +22,7 @@ import (
 	eventsapi "github.com/containerd/containerd/api/services/events/v1"
 	"github.com/containerd/containerd/errdefs"
 	"github.com/containerd/containerd/events"
+	"github.com/containerd/containerd/protobuf"
 	"github.com/containerd/typeurl"
 )
 
@@ -51,7 +52,7 @@ func (e *eventRemote) Publish(ctx context.Context, topic string, event events.Ev
 	}
 	req := &eventsapi.PublishRequest{
 		Topic: topic,
-		Event: any,
+		Event: protobuf.FromAny(any),
 	}
 	if _, err := e.client.Publish(ctx, req); err != nil {
 		return errdefs.FromGRPC(err)
@@ -65,7 +66,7 @@ func (e *eventRemote) Forward(ctx context.Context, envelope *events.Envelope) er
 			Timestamp: envelope.Timestamp,
 			Namespace: envelope.Namespace,
 			Topic:     envelope.Topic,
-			Event:     envelope.Event,
+			Event:     protobuf.FromAny(envelope.Event),
 		},
 	}
 	if _, err := e.client.Forward(ctx, req); err != nil {
diff --git a/events/events.go b/events/events.go
index b7eb86f1e..8af0ec03a 100644
--- a/events/events.go
+++ b/events/events.go
@@ -21,7 +21,6 @@ import (
 	"time"
 
 	"github.com/containerd/typeurl"
-	"github.com/gogo/protobuf/types"
 )
 
 // Envelope provides the packaging for an event.
@@ -29,7 +28,7 @@ type Envelope struct {
 	Timestamp time.Time
 	Namespace string
 	Topic     string
-	Event     *types.Any
+	Event     typeurl.Any
 }
 
 // Field returns the value for the given fieldpath as a string, if defined.
diff --git a/events/exchange/exchange.go b/events/exchange/exchange.go
index a1f385d7a..7f085dc91 100644
--- a/events/exchange/exchange.go
+++ b/events/exchange/exchange.go
@@ -30,7 +30,6 @@ import (
 	"github.com/containerd/containerd/namespaces"
 	"github.com/containerd/typeurl"
 	goevents "github.com/docker/go-events"
-	"github.com/gogo/protobuf/types"
 	"github.com/sirupsen/logrus"
 )
 
@@ -63,7 +62,7 @@ func (e *Exchange) Forward(ctx context.Context, envelope *events.Envelope) (err
 		logger := log.G(ctx).WithFields(logrus.Fields{
 			"topic": envelope.Topic,
 			"ns":    envelope.Namespace,
-			"type":  envelope.Event.TypeUrl,
+			"type":  envelope.Event.GetTypeUrl(),
 		})
 
 		if err != nil {
@@ -82,7 +81,6 @@ func (e *Exchange) Forward(ctx context.Context, envelope *events.Envelope) (err
 func (e *Exchange) Publish(ctx context.Context, topic string, event events.Event) (err error) {
 	var (
 		namespace string
-		encoded   *types.Any
 		envelope  events.Envelope
 	)
 
@@ -94,7 +92,7 @@ func (e *Exchange) Publish(ctx context.Context, topic string, event events.Event
 		return fmt.Errorf("envelope topic %q: %w", topic, err)
 	}
 
-	encoded, err = typeurl.MarshalAny(event)
+	encoded, err := typeurl.MarshalAny(event)
 	if err != nil {
 		return err
 	}
@@ -108,7 +106,7 @@ func (e *Exchange) Publish(ctx context.Context, topic string, event events.Event
 		logger := log.G(ctx).WithFields(logrus.Fields{
 			"topic": envelope.Topic,
 			"ns":    envelope.Namespace,
-			"type":  envelope.Event.TypeUrl,
+			"type":  envelope.Event.GetTypeUrl(),
 		})
 
 		if err != nil {
diff --git a/go.mod b/go.mod
index e49859e83..61cea501a 100644
--- a/go.mod
+++ b/go.mod
@@ -17,7 +17,7 @@ require (
 	github.com/containerd/imgcrypt v1.1.4
 	github.com/containerd/nri v0.1.0
 	github.com/containerd/ttrpc v1.1.0
-	github.com/containerd/typeurl v1.0.2
+	github.com/containerd/typeurl v1.0.3-0.20220324183432-6193a0e03259
 	github.com/containerd/zfs v1.0.0
 	github.com/containernetworking/plugins v1.1.1
 	github.com/coreos/go-systemd/v22 v22.3.2
diff --git a/go.sum b/go.sum
index fa93eb9ff..dc179935a 100644
--- a/go.sum
+++ b/go.sum
@@ -257,8 +257,9 @@ github.com/containerd/ttrpc v1.1.0/go.mod h1:XX4ZTnoOId4HklF4edwc4DcqskFZuvXB1Ev
 github.com/containerd/typeurl v0.0.0-20180627222232-a93fcdb778cd/go.mod h1:Cm3kwCdlkCfMSHURc+r6fwoGH6/F1hH3S4sg0rLFWPc=
 github.com/containerd/typeurl v0.0.0-20190911142611-5eb25027c9fd/go.mod h1:GeKYzf2pQcqv7tJ0AoCuuhtnqhva5LNU3U+OyKxxJpk=
 github.com/containerd/typeurl v1.0.1/go.mod h1:TB1hUtrpaiO88KEK56ijojHS1+NeF0izUACaJW2mdXg=
-github.com/containerd/typeurl v1.0.2 h1:Chlt8zIieDbzQFzXzAeBEF92KhExuE4p9p92/QmY7aY=
 github.com/containerd/typeurl v1.0.2/go.mod h1:9trJWW2sRlGub4wZJRTW83VtbOLS6hwcDZXTn6oPz9s=
+github.com/containerd/typeurl v1.0.3-0.20220324183432-6193a0e03259 h1:bJv9qgjarrsdd4XIIczeRdYXON88Fgn3GdXVfnQjcSo=
+github.com/containerd/typeurl v1.0.3-0.20220324183432-6193a0e03259/go.mod h1:HDkcKOXRnX6yKnXv3P0QrogFi0DoiauK/LpQi961f0A=
 github.com/containerd/zfs v0.0.0-20200918131355-0a33824f23a2/go.mod h1:8IgZOBdv8fAgXddBT4dBXJPtxyRsejFIpXoklgxgEjw=
 github.com/containerd/zfs v0.0.0-20210301145711-11e8f1707f62/go.mod h1:A9zfAbMlQwE+/is6hi0Xw8ktpL+6glmqZYtevJgaB8Y=
 github.com/containerd/zfs v0.0.0-20210315114300-dde8f0fda960/go.mod h1:m+m51S1DvAP6r3FcmYCp54bQ34pyOwTieQDNRIRHsFY=
diff --git a/integration/client/container_test.go b/integration/client/container_test.go
index d05ebd1ec..c12645e66 100644
--- a/integration/client/container_test.go
+++ b/integration/client/container_test.go
@@ -1440,11 +1440,11 @@ func TestContainerExtensions(t *testing.T) {
 		if len(cExts) != 1 {
 			t.Errorf("expected 1 container extension")
 		}
-		if cExts["hello"].TypeUrl != ext.TypeUrl {
-			t.Errorf("got unexpected type url for extension: %s", cExts["hello"].TypeUrl)
+		if actual := cExts["hello"].GetTypeUrl(); actual != ext.TypeUrl {
+			t.Errorf("got unexpected type url for extension: %s", actual)
 		}
-		if !bytes.Equal(cExts["hello"].Value, ext.Value) {
-			t.Errorf("expected extension value %q, got: %q", ext.Value, cExts["hello"].Value)
+		if actual := cExts["hello"].GetValue(); !bytes.Equal(actual, ext.Value) {
+			t.Errorf("expected extension value %q, got: %q", ext.Value, actual)
 		}
 	}
 
diff --git a/integration/client/go.mod b/integration/client/go.mod
index f8aaabd20..542d2ce8f 100644
--- a/integration/client/go.mod
+++ b/integration/client/go.mod
@@ -10,7 +10,7 @@ require (
 	github.com/containerd/containerd v1.6.1
 	github.com/containerd/go-runc v1.0.0
 	github.com/containerd/ttrpc v1.1.0
-	github.com/containerd/typeurl v1.0.2
+	github.com/containerd/typeurl v1.0.3-0.20220324183432-6193a0e03259
 	github.com/gogo/protobuf v1.3.2
 	github.com/opencontainers/go-digest v1.0.0
 	github.com/opencontainers/image-spec v1.0.3-0.20211202183452-c5a74bcca799
diff --git a/integration/client/go.sum b/integration/client/go.sum
index 0d6a9ef9b..f6bd8ea5b 100644
--- a/integration/client/go.sum
+++ b/integration/client/go.sum
@@ -145,8 +145,9 @@ github.com/containerd/ttrpc v1.0.2/go.mod h1:UAxOpgT9ziI0gJrmKvgcZivgxOp8iFPSk8h
 github.com/containerd/ttrpc v1.1.0 h1:GbtyLRxb0gOLR0TYQWt3O6B0NvT8tMdorEHqIQo/lWI=
 github.com/containerd/ttrpc v1.1.0/go.mod h1:XX4ZTnoOId4HklF4edwc4DcqskFZuvXB1Evzy5KFQpQ=
 github.com/containerd/typeurl v1.0.1/go.mod h1:TB1hUtrpaiO88KEK56ijojHS1+NeF0izUACaJW2mdXg=
-github.com/containerd/typeurl v1.0.2 h1:Chlt8zIieDbzQFzXzAeBEF92KhExuE4p9p92/QmY7aY=
 github.com/containerd/typeurl v1.0.2/go.mod h1:9trJWW2sRlGub4wZJRTW83VtbOLS6hwcDZXTn6oPz9s=
+github.com/containerd/typeurl v1.0.3-0.20220324183432-6193a0e03259 h1:bJv9qgjarrsdd4XIIczeRdYXON88Fgn3GdXVfnQjcSo=
+github.com/containerd/typeurl v1.0.3-0.20220324183432-6193a0e03259/go.mod h1:HDkcKOXRnX6yKnXv3P0QrogFi0DoiauK/LpQi961f0A=
 github.com/containerd/zfs v1.0.0/go.mod h1:m+m51S1DvAP6r3FcmYCp54bQ34pyOwTieQDNRIRHsFY=
 github.com/containernetworking/cni v1.0.1/go.mod h1:AKuhXbN5EzmD4yTNtfSsX3tPcmtrBI6QcRV0NiNt15Y=
 github.com/containernetworking/cni v1.1.1/go.mod h1:sDpYKmGVENF3s6uvMvGgldDWeG8dMxakj/u+i9ht9vw=
diff --git a/metadata/boltutil/helpers.go b/metadata/boltutil/helpers.go
index 4722a5226..2b2b0ad1e 100644
--- a/metadata/boltutil/helpers.go
+++ b/metadata/boltutil/helpers.go
@@ -20,6 +20,8 @@ import (
 	"fmt"
 	"time"
 
+	"github.com/containerd/containerd/protobuf"
+	"github.com/containerd/typeurl"
 	"github.com/gogo/protobuf/proto"
 	"github.com/gogo/protobuf/types"
 	bolt "go.etcd.io/bbolt"
@@ -151,7 +153,7 @@ func WriteTimestamps(bkt *bolt.Bucket, created, updated time.Time) error {
 
 // WriteExtensions will write a KV map to the given bucket,
 // where `K` is a string key and `V` is a protobuf's Any type that represents a generic extension.
-func WriteExtensions(bkt *bolt.Bucket, extensions map[string]types.Any) error {
+func WriteExtensions(bkt *bolt.Bucket, extensions map[string]typeurl.Any) error {
 	if len(extensions) == 0 {
 		return nil
 	}
@@ -162,7 +164,8 @@ func WriteExtensions(bkt *bolt.Bucket, extensions map[string]types.Any) error {
 	}
 
 	for name, ext := range extensions {
-		p, err := proto.Marshal(&ext)
+		ext := protobuf.FromAny(ext)
+		p, err := proto.Marshal(ext)
 		if err != nil {
 			return err
 		}
@@ -176,9 +179,9 @@ func WriteExtensions(bkt *bolt.Bucket, extensions map[string]types.Any) error {
 }
 
 // ReadExtensions will read back a map of extensions from the given bucket, previously written by WriteExtensions
-func ReadExtensions(bkt *bolt.Bucket) (map[string]types.Any, error) {
+func ReadExtensions(bkt *bolt.Bucket) (map[string]typeurl.Any, error) {
 	var (
-		extensions = make(map[string]types.Any)
+		extensions = make(map[string]typeurl.Any)
 		ebkt       = bkt.Bucket(bucketKeyExtensions)
 	)
 
@@ -192,7 +195,7 @@ func ReadExtensions(bkt *bolt.Bucket) (map[string]types.Any, error) {
 			return err
 		}
 
-		extensions[string(k)] = t
+		extensions[string(k)] = &t
 		return nil
 	}); err != nil {
 		return nil, err
@@ -202,12 +205,13 @@ func ReadExtensions(bkt *bolt.Bucket) (map[string]types.Any, error) {
 }
 
 // WriteAny write a protobuf's Any type to the bucket
-func WriteAny(bkt *bolt.Bucket, name []byte, any *types.Any) error {
-	if any == nil {
+func WriteAny(bkt *bolt.Bucket, name []byte, any typeurl.Any) error {
+	pbany := protobuf.FromAny(any)
+	if pbany == nil {
 		return nil
 	}
 
-	data, err := proto.Marshal(any)
+	data, err := proto.Marshal(pbany)
 	if err != nil {
 		return err
 	}
diff --git a/metadata/containers.go b/metadata/containers.go
index 97002e588..b27dc0f87 100644
--- a/metadata/containers.go
+++ b/metadata/containers.go
@@ -30,6 +30,7 @@ import (
 	"github.com/containerd/containerd/labels"
 	"github.com/containerd/containerd/metadata/boltutil"
 	"github.com/containerd/containerd/namespaces"
+	"github.com/containerd/typeurl"
 	"github.com/gogo/protobuf/proto"
 	"github.com/gogo/protobuf/types"
 	bolt "go.etcd.io/bbolt"
@@ -211,7 +212,7 @@ func (s *containerStore) Update(ctx context.Context, container containers.Contai
 
 			if strings.HasPrefix(path, "extensions.") {
 				if updated.Extensions == nil {
-					updated.Extensions = map[string]types.Any{}
+					updated.Extensions = map[string]typeurl.Any{}
 				}
 				key := strings.TrimPrefix(path, "extensions.")
 				updated.Extensions[key] = container.Extensions[key]
diff --git a/metadata/containers_test.go b/metadata/containers_test.go
index c0192a458..7be6e0f2d 100644
--- a/metadata/containers_test.go
+++ b/metadata/containers_test.go
@@ -32,10 +32,13 @@ import (
 	"github.com/containerd/containerd/filters"
 	"github.com/containerd/containerd/log/logtest"
 	"github.com/containerd/containerd/namespaces"
+	"github.com/containerd/containerd/protobuf"
 	"github.com/containerd/typeurl"
 	"github.com/gogo/protobuf/types"
+	"github.com/google/go-cmp/cmp"
 	specs "github.com/opencontainers/runtime-spec/specs-go"
 	bolt "go.etcd.io/bbolt"
+	"gotest.tools/v3/assert"
 )
 
 func init() {
@@ -49,7 +52,7 @@ func TestContainersList(t *testing.T) {
 	store := NewContainerStore(NewDB(db, nil, nil))
 
 	spec := &specs.Spec{}
-	encoded, err := typeurl.MarshalAny(spec)
+	encoded, err := protobuf.MarshalAnyToProto(spec)
 	if err != nil {
 		t.Fatal(err)
 	}
@@ -180,13 +183,13 @@ func TestContainersCreateUpdateDelete(t *testing.T) {
 	store := NewContainerStore(NewDB(db, nil, nil))
 
 	spec := &specs.Spec{}
-	encoded, err := typeurl.MarshalAny(spec)
+	encoded, err := protobuf.MarshalAnyToProto(spec)
 	if err != nil {
 		t.Fatal(err)
 	}
 
 	spec.Annotations = map[string]string{"updated": "true"}
-	encodedUpdated, err := typeurl.MarshalAny(spec)
+	encodedUpdated, err := protobuf.MarshalAnyToProto(spec)
 	if err != nil {
 		t.Fatal(err)
 	}
@@ -468,8 +471,8 @@ func TestContainersCreateUpdateDelete(t *testing.T) {
 				Runtime: containers.RuntimeInfo{
 					Name: "testruntime",
 				},
-				Extensions: map[string]types.Any{
-					"hello": {
+				Extensions: map[string]typeurl.Any{
+					"hello": &types.Any{
 						TypeUrl: "test.update.extensions",
 						Value:   []byte("hello"),
 					},
@@ -480,8 +483,8 @@ func TestContainersCreateUpdateDelete(t *testing.T) {
 				Runtime: containers.RuntimeInfo{
 					Name: "testruntime",
 				},
-				Extensions: map[string]types.Any{
-					"hello": {
+				Extensions: map[string]typeurl.Any{
+					"hello": &types.Any{
 						TypeUrl: "test.update.extensions",
 						Value:   []byte("world"),
 					},
@@ -492,8 +495,8 @@ func TestContainersCreateUpdateDelete(t *testing.T) {
 				Runtime: containers.RuntimeInfo{
 					Name: "testruntime",
 				},
-				Extensions: map[string]types.Any{
-					"hello": {
+				Extensions: map[string]typeurl.Any{
+					"hello": &types.Any{
 						TypeUrl: "test.update.extensions",
 						Value:   []byte("world"),
 					},
@@ -507,8 +510,8 @@ func TestContainersCreateUpdateDelete(t *testing.T) {
 				Runtime: containers.RuntimeInfo{
 					Name: "testruntime",
 				},
-				Extensions: map[string]types.Any{
-					"hello": {
+				Extensions: map[string]typeurl.Any{
+					"hello": &types.Any{
 						TypeUrl: "test.update.extensions",
 						Value:   []byte("hello"),
 					},
@@ -519,8 +522,8 @@ func TestContainersCreateUpdateDelete(t *testing.T) {
 				Runtime: containers.RuntimeInfo{
 					Name: "testruntime",
 				},
-				Extensions: map[string]types.Any{
-					"hello": {
+				Extensions: map[string]typeurl.Any{
+					"hello": &types.Any{
 						TypeUrl: "test.update.extensions",
 						Value:   []byte("world"),
 					},
@@ -532,8 +535,8 @@ func TestContainersCreateUpdateDelete(t *testing.T) {
 				Runtime: containers.RuntimeInfo{
 					Name: "testruntime",
 				},
-				Extensions: map[string]types.Any{
-					"hello": {
+				Extensions: map[string]typeurl.Any{
+					"hello": &types.Any{
 						TypeUrl: "test.update.extensions",
 						Value:   []byte("hello"),
 					},
@@ -547,8 +550,8 @@ func TestContainersCreateUpdateDelete(t *testing.T) {
 				Runtime: containers.RuntimeInfo{
 					Name: "testruntime",
 				},
-				Extensions: map[string]types.Any{
-					"hello": {
+				Extensions: map[string]typeurl.Any{
+					"hello": &types.Any{
 						TypeUrl: "test.update.extensions",
 						Value:   []byte("hello"),
 					},
@@ -558,8 +561,8 @@ func TestContainersCreateUpdateDelete(t *testing.T) {
 				Labels: map[string]string{
 					"foo": "one",
 				},
-				Extensions: map[string]types.Any{
-					"hello": {
+				Extensions: map[string]typeurl.Any{
+					"hello": &types.Any{
 						TypeUrl: "test.update.extensions",
 						Value:   []byte("world"),
 					},
@@ -571,8 +574,8 @@ func TestContainersCreateUpdateDelete(t *testing.T) {
 				Runtime: containers.RuntimeInfo{
 					Name: "testruntime",
 				},
-				Extensions: map[string]types.Any{
-					"hello": {
+				Extensions: map[string]typeurl.Any{
+					"hello": &types.Any{
 						TypeUrl: "test.update.extensions",
 						Value:   []byte("world"),
 					},
@@ -586,21 +589,21 @@ func TestContainersCreateUpdateDelete(t *testing.T) {
 				Runtime: containers.RuntimeInfo{
 					Name: "testruntime",
 				},
-				Extensions: map[string]types.Any{
+				Extensions: map[string]typeurl.Any{
 					// leaves hello in place.
-					"hello": {
+					"hello": &types.Any{
 						TypeUrl: "test.update.extensions",
 						Value:   []byte("hello"),
 					},
 				},
 			},
 			input: containers.Container{
-				Extensions: map[string]types.Any{
-					"hello": {
+				Extensions: map[string]typeurl.Any{
+					"hello": &types.Any{
 						TypeUrl: "test.update.extensions",
 						Value:   []byte("universe"), // this will be ignored
 					},
-					"bar": {
+					"bar": &types.Any{
 						TypeUrl: "test.update.extensions",
 						Value:   []byte("foo"), // this will be added
 					},
@@ -612,12 +615,12 @@ func TestContainersCreateUpdateDelete(t *testing.T) {
 				Runtime: containers.RuntimeInfo{
 					Name: "testruntime",
 				},
-				Extensions: map[string]types.Any{
-					"hello": {
+				Extensions: map[string]typeurl.Any{
+					"hello": &types.Any{
 						TypeUrl: "test.update.extensions",
 						Value:   []byte("hello"), // remains as world
 					},
-					"bar": {
+					"bar": &types.Any{
 						TypeUrl: "test.update.extensions",
 						Value:   []byte("foo"), // this will be added
 					},
@@ -703,10 +706,26 @@ func checkContainerTimestamps(t *testing.T, c *containers.Container, now time.Ti
 	}
 }
 
-func checkContainersEqual(t *testing.T, a, b *containers.Container, format string, args ...interface{}) {
-	if !reflect.DeepEqual(a, b) {
-		t.Fatalf("containers not equal \n\t%v != \n\t%v: "+format, append([]interface{}{a, b}, args...)...)
+// isNil returns true if the given parameter is nil or typed nil.
+func isNil(x interface{}) bool {
+	if x == nil {
+		return true
 	}
+	v := reflect.ValueOf(x)
+	return v.Kind() == reflect.Ptr && v.IsNil()
+}
+
+func checkContainersEqual(t *testing.T, a, b *containers.Container, format string, args ...interface{}) {
+	// Ignore the difference of nil and typed nil.
+	opt := cmp.FilterValues(
+		func(x, y interface{}) bool {
+			return isNil(x) && isNil(y)
+		},
+		cmp.Comparer(func(_, _ interface{}) bool {
+			return true
+		}),
+	)
+	assert.DeepEqual(t, a, b, opt)
 }
 
 func testEnv(t *testing.T) (context.Context, *bolt.DB, func()) {
diff --git a/pkg/cri/server/events.go b/pkg/cri/server/events.go
index b98dd1fd3..ca817d0fb 100644
--- a/pkg/cri/server/events.go
+++ b/pkg/cri/server/events.go
@@ -32,7 +32,6 @@ import (
 	sandboxstore "github.com/containerd/containerd/pkg/cri/store/sandbox"
 	ctrdutil "github.com/containerd/containerd/pkg/cri/util"
 	"github.com/containerd/typeurl"
-	gogotypes "github.com/gogo/protobuf/types"
 	"github.com/sirupsen/logrus"
 	"golang.org/x/net/context"
 	"k8s.io/utils/clock"
@@ -207,7 +206,7 @@ func (em *eventMonitor) startContainerExitMonitor(ctx context.Context, id string
 	return stopCh
 }
 
-func convertEvent(e *gogotypes.Any) (string, interface{}, error) {
+func convertEvent(e typeurl.Any) (string, interface{}, error) {
 	id := ""
 	evt, err := typeurl.UnmarshalAny(e)
 	if err != nil {
diff --git a/pkg/cri/server/helpers.go b/pkg/cri/server/helpers.go
index abc66e389..de9bdddc1 100644
--- a/pkg/cri/server/helpers.go
+++ b/pkg/cri/server/helpers.go
@@ -374,10 +374,11 @@ func getRuntimeOptionsType(t string) interface{} {
 
 // getRuntimeOptions get runtime options from container metadata.
 func getRuntimeOptions(c containers.Container) (interface{}, error) {
-	if c.Runtime.Options == nil {
+	from := c.Runtime.Options
+	if from == nil || from.GetValue() == nil {
 		return nil, nil
 	}
-	opts, err := typeurl.UnmarshalAny(c.Runtime.Options)
+	opts, err := typeurl.UnmarshalAny(from)
 	if err != nil {
 		return nil, err
 	}
diff --git a/pkg/cri/server/helpers_test.go b/pkg/cri/server/helpers_test.go
index c0c1c6e75..f22c05b56 100644
--- a/pkg/cri/server/helpers_test.go
+++ b/pkg/cri/server/helpers_test.go
@@ -23,6 +23,7 @@ import (
 	"testing"
 	"time"
 
+	"github.com/containerd/containerd/containers"
 	"github.com/containerd/containerd/errdefs"
 	"github.com/containerd/containerd/oci"
 	criconfig "github.com/containerd/containerd/pkg/cri/config"
@@ -32,6 +33,8 @@ import (
 	"github.com/containerd/containerd/reference/docker"
 	"github.com/containerd/containerd/runtime/linux/runctypes"
 	runcoptions "github.com/containerd/containerd/runtime/v2/runc/options"
+	"github.com/containerd/typeurl"
+	"github.com/gogo/protobuf/types"
 
 	imagedigest "github.com/opencontainers/go-digest"
 	runtimespec "github.com/opencontainers/runtime-spec/specs-go"
@@ -602,3 +605,13 @@ func TestValidateTargetContainer(t *testing.T) {
 	}
 
 }
+
+func TestGetRuntimeOptions(t *testing.T) {
+	_, err := getRuntimeOptions(containers.Container{})
+	require.NoError(t, err)
+
+	var pbany *types.Any               // This is nil.
+	var typeurlAny typeurl.Any = pbany // This is typed nil.
+	_, err = getRuntimeOptions(containers.Container{Runtime: containers.RuntimeInfo{Options: typeurlAny}})
+	require.NoError(t, err)
+}
diff --git a/pkg/cri/server/restart.go b/pkg/cri/server/restart.go
index f5f3e5083..f7db3f7b3 100644
--- a/pkg/cri/server/restart.go
+++ b/pkg/cri/server/restart.go
@@ -166,7 +166,7 @@ func (c *criService) loadContainer(ctx context.Context, cntr containerd.Containe
 	if !ok {
 		return container, fmt.Errorf("metadata extension %q not found", containerMetadataExtension)
 	}
-	data, err := typeurl.UnmarshalAny(&ext)
+	data, err := typeurl.UnmarshalAny(ext)
 	if err != nil {
 		return container, fmt.Errorf("failed to unmarshal metadata extension %q: %w", ext, err)
 	}
@@ -335,7 +335,7 @@ func (c *criService) loadSandbox(ctx context.Context, cntr containerd.Container)
 	if !ok {
 		return sandbox, fmt.Errorf("metadata extension %q not found", sandboxMetadataExtension)
 	}
-	data, err := typeurl.UnmarshalAny(&ext)
+	data, err := typeurl.UnmarshalAny(ext)
 	if err != nil {
 		return sandbox, fmt.Errorf("failed to unmarshal metadata extension %q: %w", ext, err)
 	}
diff --git a/protobuf/any.go b/protobuf/any.go
new file mode 100644
index 000000000..0f6671765
--- /dev/null
+++ b/protobuf/any.go
@@ -0,0 +1,47 @@
+/*
+   Copyright The containerd Authors.
+
+   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 protobuf
+
+import (
+	"github.com/containerd/typeurl"
+	"github.com/gogo/protobuf/types"
+)
+
+// FromAny converts typeurl.Any to github.com/gogo/protobuf/types.Any.
+func FromAny(from typeurl.Any) *types.Any {
+	if from == nil {
+		return nil
+	}
+
+	if pbany, ok := from.(*types.Any); ok {
+		return pbany
+	}
+
+	return &types.Any{
+		TypeUrl: from.GetTypeUrl(),
+		Value:   from.GetValue(),
+	}
+}
+
+// FromAny converts an arbitrary interface to github.com/gogo/protobuf/types.Any.
+func MarshalAnyToProto(from interface{}) (*types.Any, error) {
+	any, err := typeurl.MarshalAny(from)
+	if err != nil {
+		return nil, err
+	}
+	return FromAny(any), nil
+}
diff --git a/protobuf/any_test.go b/protobuf/any_test.go
new file mode 100644
index 000000000..7a74ec16c
--- /dev/null
+++ b/protobuf/any_test.go
@@ -0,0 +1,26 @@
+/*
+   Copyright The containerd Authors.
+
+   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 protobuf
+
+import "testing"
+
+func TestFromAny(t *testing.T) {
+	actual := FromAny(nil)
+	if actual != nil {
+		t.Fatalf("expected nil, got %v", actual)
+	}
+}
diff --git a/runtime/runtime.go b/runtime/runtime.go
index 84aaa8ac6..1ca22ee2b 100644
--- a/runtime/runtime.go
+++ b/runtime/runtime.go
@@ -21,7 +21,7 @@ import (
 	"time"
 
 	"github.com/containerd/containerd/mount"
-	"github.com/gogo/protobuf/types"
+	"github.com/containerd/typeurl"
 )
 
 // IO holds process IO information
@@ -35,7 +35,7 @@ type IO struct {
 // CreateOpts contains task creation data
 type CreateOpts struct {
 	// Spec is the OCI runtime spec
-	Spec *types.Any
+	Spec typeurl.Any
 	// Rootfs mounts to perform to gain access to the container's filesystem
 	Rootfs []mount.Mount
 	// IO for the container's main process
@@ -43,9 +43,9 @@ type CreateOpts struct {
 	// Checkpoint digest to restore container state
 	Checkpoint string
 	// RuntimeOptions for the runtime
-	RuntimeOptions *types.Any
+	RuntimeOptions typeurl.Any
 	// TaskOptions received for the task
-	TaskOptions *types.Any
+	TaskOptions typeurl.Any
 	// Runtime name to use (e.g. `io.containerd.NAME.VERSION`).
 	// As an alternative full abs path to binary may be specified instead.
 	Runtime string
diff --git a/runtime/v1/linux/runtime.go b/runtime/v1/linux/runtime.go
index b6d53820a..ad7a0b67e 100644
--- a/runtime/v1/linux/runtime.go
+++ b/runtime/v1/linux/runtime.go
@@ -41,6 +41,7 @@ import (
 	"github.com/containerd/containerd/pkg/process"
 	"github.com/containerd/containerd/platforms"
 	"github.com/containerd/containerd/plugin"
+	"github.com/containerd/containerd/protobuf"
 	"github.com/containerd/containerd/runtime"
 	"github.com/containerd/containerd/runtime/linux/runctypes"
 	v1 "github.com/containerd/containerd/runtime/v1"
@@ -178,7 +179,7 @@ func (r *Runtime) Create(ctx context.Context, id string, opts runtime.CreateOpts
 	bundle, err := newBundle(id,
 		filepath.Join(r.state, namespace),
 		filepath.Join(r.root, namespace),
-		opts.Spec.Value)
+		opts.Spec.GetValue())
 	if err != nil {
 		return nil, err
 	}
@@ -191,7 +192,7 @@ func (r *Runtime) Create(ctx context.Context, id string, opts runtime.CreateOpts
 	shimopt := ShimLocal(r.config, r.events)
 	if !r.config.NoShim {
 		var cgroup string
-		if opts.TaskOptions != nil {
+		if opts.TaskOptions != nil && opts.TaskOptions.GetValue() != nil {
 			v, err := typeurl.UnmarshalAny(opts.TaskOptions)
 			if err != nil {
 				return nil, err
@@ -244,7 +245,7 @@ func (r *Runtime) Create(ctx context.Context, id string, opts runtime.CreateOpts
 		Stderr:     opts.IO.Stderr,
 		Terminal:   opts.IO.Terminal,
 		Checkpoint: opts.Checkpoint,
-		Options:    opts.TaskOptions,
+		Options:    protobuf.FromAny(opts.TaskOptions),
 	}
 	for _, m := range opts.Rootfs {
 		sopts.Rootfs = append(sopts.Rootfs, &types.Mount{
@@ -537,7 +538,7 @@ func (r *Runtime) getRuncOptions(ctx context.Context, id string) (*runctypes.Run
 		return nil, err
 	}
 
-	if container.Runtime.Options != nil {
+	if container.Runtime.Options != nil && container.Runtime.Options.GetValue() != nil {
 		v, err := typeurl.UnmarshalAny(container.Runtime.Options)
 		if err != nil {
 			return nil, err
diff --git a/runtime/v1/linux/task.go b/runtime/v1/linux/task.go
index 3ac7839ff..44c89e5c2 100644
--- a/runtime/v1/linux/task.go
+++ b/runtime/v1/linux/task.go
@@ -32,11 +32,11 @@ import (
 	"github.com/containerd/containerd/events/exchange"
 	"github.com/containerd/containerd/identifiers"
 	"github.com/containerd/containerd/log"
+	"github.com/containerd/containerd/protobuf"
 	"github.com/containerd/containerd/runtime"
 	"github.com/containerd/containerd/runtime/v1/shim/client"
 	"github.com/containerd/containerd/runtime/v1/shim/v1"
 	"github.com/containerd/ttrpc"
-	"github.com/containerd/typeurl"
 	"github.com/gogo/protobuf/types"
 )
 
@@ -340,7 +340,7 @@ func (t *Task) Stats(ctx context.Context) (*types.Any, error) {
 	if err != nil {
 		return nil, err
 	}
-	return typeurl.MarshalAny(stats)
+	return protobuf.MarshalAnyToProto(stats)
 }
 
 // Cgroup returns the underlying cgroup for a linux task
diff --git a/runtime/v1/shim/service.go b/runtime/v1/shim/service.go
index a08757d0a..926134821 100644
--- a/runtime/v1/shim/service.go
+++ b/runtime/v1/shim/service.go
@@ -37,6 +37,7 @@ import (
 	"github.com/containerd/containerd/namespaces"
 	"github.com/containerd/containerd/pkg/process"
 	"github.com/containerd/containerd/pkg/stdio"
+	"github.com/containerd/containerd/protobuf"
 	"github.com/containerd/containerd/runtime"
 	"github.com/containerd/containerd/runtime/linux/runctypes"
 	shimapi "github.com/containerd/containerd/runtime/v1/shim/v1"
@@ -412,7 +413,7 @@ func (s *Service) ListPids(ctx context.Context, r *shimapi.ListPidsRequest) (*sh
 				if err != nil {
 					return nil, fmt.Errorf("failed to marshal process %d info: %w", pid, err)
 				}
-				pInfo.Info = a
+				pInfo.Info = protobuf.FromAny(a)
 				break
 			}
 		}
diff --git a/runtime/v2/manager.go b/runtime/v2/manager.go
index 1927cbb3f..505d5d896 100644
--- a/runtime/v2/manager.go
+++ b/runtime/v2/manager.go
@@ -33,6 +33,7 @@ import (
 	"github.com/containerd/containerd/pkg/timeout"
 	"github.com/containerd/containerd/platforms"
 	"github.com/containerd/containerd/plugin"
+	"github.com/containerd/containerd/protobuf"
 	"github.com/containerd/containerd/runtime"
 	shimbinary "github.com/containerd/containerd/runtime/v2/shim"
 	"github.com/containerd/containerd/runtime/v2/task"
@@ -156,7 +157,7 @@ func (m *ShimManager) ID() string {
 
 // Start launches a new shim instance
 func (m *ShimManager) Start(ctx context.Context, id string, opts runtime.CreateOpts) (_ ShimProcess, retErr error) {
-	bundle, err := NewBundle(ctx, m.root, m.state, id, opts.Spec.Value)
+	bundle, err := NewBundle(ctx, m.root, m.state, id, opts.Spec.GetValue())
 	if err != nil {
 		return nil, err
 	}
@@ -197,7 +198,7 @@ func (m *ShimManager) startShim(ctx context.Context, bundle *Bundle, id string,
 	}
 
 	topts := opts.TaskOptions
-	if topts == nil {
+	if topts == nil || topts.GetValue() == nil {
 		topts = opts.RuntimeOptions
 	}
 
@@ -212,7 +213,7 @@ func (m *ShimManager) startShim(ctx context.Context, bundle *Bundle, id string,
 		ttrpcAddress: m.containerdTTRPCAddress,
 		schedCore:    m.schedCore,
 	})
-	shim, err := b.Start(ctx, topts, func() {
+	shim, err := b.Start(ctx, protobuf.FromAny(topts), func() {
 		log.G(ctx).WithField("id", id).Info("shim disconnected")
 
 		cleanupAfterDeadShim(context.Background(), id, ns, m.shims, m.events, b)
diff --git a/runtime/v2/runc/container.go b/runtime/v2/runc/container.go
index 4da91d691..3683868e0 100644
--- a/runtime/v2/runc/container.go
+++ b/runtime/v2/runc/container.go
@@ -49,12 +49,14 @@ func NewContainer(ctx context.Context, platform stdio.Platform, r *task.CreateTa
 	}
 
 	var opts options.Options
-	if r.Options != nil && r.Options.GetTypeUrl() != "" {
+	if r.Options.GetValue() != nil {
 		v, err := typeurl.UnmarshalAny(r.Options)
 		if err != nil {
 			return nil, err
 		}
-		opts = *v.(*options.Options)
+		if v != nil {
+			opts = *v.(*options.Options)
+		}
 	}
 
 	var mounts []process.Mount
diff --git a/runtime/v2/runc/task/service.go b/runtime/v2/runc/task/service.go
index 4ad70dad3..1d6ff1714 100644
--- a/runtime/v2/runc/task/service.go
+++ b/runtime/v2/runc/task/service.go
@@ -38,6 +38,7 @@ import (
 	"github.com/containerd/containerd/pkg/shutdown"
 	"github.com/containerd/containerd/pkg/stdio"
 	"github.com/containerd/containerd/pkg/userns"
+	"github.com/containerd/containerd/protobuf"
 	"github.com/containerd/containerd/runtime/v2/runc"
 	"github.com/containerd/containerd/runtime/v2/runc/options"
 	"github.com/containerd/containerd/runtime/v2/shim"
@@ -375,7 +376,7 @@ func (s *service) Pids(ctx context.Context, r *taskAPI.PidsRequest) (*taskAPI.Pi
 				d := &options.ProcessDetails{
 					ExecID: p.ID(),
 				}
-				a, err := typeurl.MarshalAny(d)
+				a, err := protobuf.MarshalAnyToProto(d)
 				if err != nil {
 					return nil, fmt.Errorf("failed to marshal process %d info: %w", pid, err)
 				}
@@ -503,7 +504,7 @@ func (s *service) Stats(ctx context.Context, r *taskAPI.StatsRequest) (*taskAPI.
 		return nil, err
 	}
 	return &taskAPI.StatsResponse{
-		Stats: data,
+		Stats: protobuf.FromAny(data),
 	}, nil
 }
 
diff --git a/runtime/v2/runc/v1/service.go b/runtime/v2/runc/v1/service.go
index 0c84c1403..b27e59bbe 100644
--- a/runtime/v2/runc/v1/service.go
+++ b/runtime/v2/runc/v1/service.go
@@ -41,6 +41,7 @@ import (
 	"github.com/containerd/containerd/pkg/process"
 	"github.com/containerd/containerd/pkg/schedcore"
 	"github.com/containerd/containerd/pkg/stdio"
+	"github.com/containerd/containerd/protobuf"
 	"github.com/containerd/containerd/runtime/v2/runc"
 	"github.com/containerd/containerd/runtime/v2/runc/options"
 	"github.com/containerd/containerd/runtime/v2/shim"
@@ -507,7 +508,7 @@ func (s *service) Pids(ctx context.Context, r *taskAPI.PidsRequest) (*taskAPI.Pi
 				d := &options.ProcessDetails{
 					ExecID: p.ID(),
 				}
-				a, err := typeurl.MarshalAny(d)
+				a, err := protobuf.MarshalAnyToProto(d)
 				if err != nil {
 					return nil, fmt.Errorf("failed to marshal process %d info: %w", pid, err)
 				}
@@ -617,7 +618,7 @@ func (s *service) Stats(ctx context.Context, r *taskAPI.StatsRequest) (*taskAPI.
 		return nil, err
 	}
 	return &taskAPI.StatsResponse{
-		Stats: data,
+		Stats: protobuf.FromAny(data),
 	}, nil
 }
 
diff --git a/runtime/v2/shim.go b/runtime/v2/shim.go
index 456ffb440..18cc9a0ed 100644
--- a/runtime/v2/shim.go
+++ b/runtime/v2/shim.go
@@ -34,6 +34,7 @@ import (
 	"github.com/containerd/containerd/log"
 	"github.com/containerd/containerd/namespaces"
 	"github.com/containerd/containerd/pkg/timeout"
+	"github.com/containerd/containerd/protobuf"
 	"github.com/containerd/containerd/runtime"
 	client "github.com/containerd/containerd/runtime/v2/shim"
 	"github.com/containerd/containerd/runtime/v2/task"
@@ -324,7 +325,7 @@ func (s *shimTask) delete(ctx context.Context, removeTask func(ctx context.Conte
 
 func (s *shimTask) Create(ctx context.Context, opts runtime.CreateOpts) (runtime.Task, error) {
 	topts := opts.TaskOptions
-	if topts == nil {
+	if topts == nil || topts.GetValue() == nil {
 		topts = opts.RuntimeOptions
 	}
 	request := &task.CreateTaskRequest{
@@ -335,7 +336,7 @@ func (s *shimTask) Create(ctx context.Context, opts runtime.CreateOpts) (runtime
 		Stderr:     opts.IO.Stderr,
 		Terminal:   opts.IO.Terminal,
 		Checkpoint: opts.Checkpoint,
-		Options:    topts,
+		Options:    protobuf.FromAny(topts),
 	}
 	for _, m := range opts.Rootfs {
 		request.Rootfs = append(request.Rootfs, &types.Mount{
diff --git a/runtime/v2/shim/publisher.go b/runtime/v2/shim/publisher.go
index ed1ebdd58..20856f115 100644
--- a/runtime/v2/shim/publisher.go
+++ b/runtime/v2/shim/publisher.go
@@ -25,8 +25,8 @@ import (
 	"github.com/containerd/containerd/events"
 	"github.com/containerd/containerd/namespaces"
 	"github.com/containerd/containerd/pkg/ttrpcutil"
+	"github.com/containerd/containerd/protobuf"
 	"github.com/containerd/ttrpc"
-	"github.com/containerd/typeurl"
 	"github.com/sirupsen/logrus"
 )
 
@@ -110,7 +110,7 @@ func (l *RemoteEventsPublisher) Publish(ctx context.Context, topic string, event
 	if err != nil {
 		return err
 	}
-	any, err := typeurl.MarshalAny(event)
+	any, err := protobuf.MarshalAnyToProto(event)
 	if err != nil {
 		return err
 	}
diff --git a/services/containers/helpers.go b/services/containers/helpers.go
index dde4caed1..0c5b76fea 100644
--- a/services/containers/helpers.go
+++ b/services/containers/helpers.go
@@ -19,6 +19,9 @@ package containers
 import (
 	api "github.com/containerd/containerd/api/services/containers/v1"
 	"github.com/containerd/containerd/containers"
+	"github.com/containerd/containerd/protobuf"
+	"github.com/containerd/typeurl"
+	"github.com/gogo/protobuf/types"
 )
 
 func containersToProto(containers []containers.Container) []api.Container {
@@ -32,20 +35,24 @@ func containersToProto(containers []containers.Container) []api.Container {
 }
 
 func containerToProto(container *containers.Container) api.Container {
+	extensions := make(map[string]types.Any)
+	for k, v := range container.Extensions {
+		extensions[k] = *protobuf.FromAny(v)
+	}
 	return api.Container{
 		ID:     container.ID,
 		Labels: container.Labels,
 		Image:  container.Image,
 		Runtime: &api.Container_Runtime{
 			Name:    container.Runtime.Name,
-			Options: container.Runtime.Options,
+			Options: protobuf.FromAny(container.Runtime.Options),
 		},
-		Spec:        container.Spec,
+		Spec:        protobuf.FromAny(container.Spec),
 		Snapshotter: container.Snapshotter,
 		SnapshotKey: container.SnapshotKey,
 		CreatedAt:   container.CreatedAt,
 		UpdatedAt:   container.UpdatedAt,
-		Extensions:  container.Extensions,
+		Extensions:  extensions,
 	}
 }
 
@@ -57,6 +64,11 @@ func containerFromProto(containerpb *api.Container) containers.Container {
 			Options: containerpb.Runtime.Options,
 		}
 	}
+	extensions := make(map[string]typeurl.Any)
+	for k, v := range containerpb.Extensions {
+		v := v
+		extensions[k] = &v
+	}
 	return containers.Container{
 		ID:          containerpb.ID,
 		Labels:      containerpb.Labels,
@@ -65,6 +77,6 @@ func containerFromProto(containerpb *api.Container) containers.Container {
 		Spec:        containerpb.Spec,
 		Snapshotter: containerpb.Snapshotter,
 		SnapshotKey: containerpb.SnapshotKey,
-		Extensions:  containerpb.Extensions,
+		Extensions:  extensions,
 	}
 }
diff --git a/services/events/service.go b/services/events/service.go
index 3b5f81138..b1992a1ab 100644
--- a/services/events/service.go
+++ b/services/events/service.go
@@ -26,6 +26,7 @@ import (
 	"github.com/containerd/containerd/events"
 	"github.com/containerd/containerd/events/exchange"
 	"github.com/containerd/containerd/plugin"
+	"github.com/containerd/containerd/protobuf"
 	"github.com/containerd/ttrpc"
 	ptypes "github.com/gogo/protobuf/types"
 	"google.golang.org/grpc"
@@ -115,7 +116,7 @@ func toProto(env *events.Envelope) *api.Envelope {
 		Timestamp: env.Timestamp,
 		Namespace: env.Namespace,
 		Topic:     env.Topic,
-		Event:     env.Event,
+		Event:     protobuf.FromAny(env.Event),
 	}
 }
 
diff --git a/services/tasks/local.go b/services/tasks/local.go
index 96ed36ca4..34cb23d16 100644
--- a/services/tasks/local.go
+++ b/services/tasks/local.go
@@ -41,6 +41,7 @@ import (
 	"github.com/containerd/containerd/mount"
 	"github.com/containerd/containerd/pkg/timeout"
 	"github.com/containerd/containerd/plugin"
+	"github.com/containerd/containerd/protobuf"
 	"github.com/containerd/containerd/runtime"
 	"github.com/containerd/containerd/runtime/linux/runctypes"
 	"github.com/containerd/containerd/runtime/v2/runc/options"
@@ -461,7 +462,7 @@ func (l *local) ListPids(ctx context.Context, r *api.ListPidsRequest, _ ...grpc.
 			Pid: p.Pid,
 		}
 		if p.Info != nil {
-			a, err := typeurl.MarshalAny(p.Info)
+			a, err := protobuf.MarshalAnyToProto(p.Info)
 			if err != nil {
 				return nil, fmt.Errorf("failed to marshal process %d info: %w", p.Pid, err)
 			}
@@ -576,7 +577,7 @@ func (l *local) Checkpoint(ctx context.Context, r *api.CheckpointTaskRequest, _
 		return nil, err
 	}
 	// write the config to the content store
-	data, err := container.Spec.Marshal()
+	data, err := protobuf.FromAny(container.Spec).Marshal()
 	if err != nil {
 		return nil, err
 	}
diff --git a/task.go b/task.go
index 692d92c1d..7d8d477ab 100644
--- a/task.go
+++ b/task.go
@@ -38,6 +38,7 @@ import (
 	"github.com/containerd/containerd/mount"
 	"github.com/containerd/containerd/oci"
 	"github.com/containerd/containerd/plugin"
+	"github.com/containerd/containerd/protobuf"
 	"github.com/containerd/containerd/rootfs"
 	"github.com/containerd/containerd/runtime/linux/runctypes"
 	"github.com/containerd/containerd/runtime/v2/runc/options"
@@ -346,7 +347,7 @@ func (t *task) Exec(ctx context.Context, id string, spec *specs.Process, ioCreat
 			i.Close()
 		}
 	}()
-	any, err := typeurl.MarshalAny(spec)
+	any, err := protobuf.MarshalAnyToProto(spec)
 	if err != nil {
 		return nil, err
 	}
@@ -446,7 +447,7 @@ func (t *task) Checkpoint(ctx context.Context, opts ...CheckpointTaskOpts) (Imag
 	}
 	request.ParentCheckpoint = i.ParentCheckpoint
 	if i.Options != nil {
-		any, err := typeurl.MarshalAny(i.Options)
+		any, err := protobuf.MarshalAnyToProto(i.Options)
 		if err != nil {
 			return nil, err
 		}
@@ -535,7 +536,7 @@ func (t *task) Update(ctx context.Context, opts ...UpdateTaskOpts) error {
 		if err != nil {
 			return err
 		}
-		request.Resources = any
+		request.Resources = protobuf.FromAny(any)
 	}
 	if i.Annotations != nil {
 		request.Annotations = i.Annotations
diff --git a/metrics/cgroups/metrics_test.go b/metrics/cgroups/metrics_test.go
--- a/metrics/cgroups/metrics_test.go
+++ b/metrics/cgroups/metrics_test.go
@@ -32,7 +32,7 @@ import (
 	v2 "github.com/containerd/containerd/metrics/cgroups/v2"
 	v1types "github.com/containerd/containerd/metrics/types/v1"
 	v2types "github.com/containerd/containerd/metrics/types/v2"
-	"github.com/containerd/typeurl"
+	"github.com/containerd/containerd/protobuf"
 	"github.com/prometheus/client_golang/prometheus"
 
 	metrics "github.com/docker/go-metrics"
@@ -152,7 +152,7 @@ func (t *mockStatT) Namespace() string {
 
 func (t *mockStatT) Stats(context.Context) (*types.Any, error) {
 	if t.isV1 {
-		return typeurl.MarshalAny(&v1types.Metrics{})
+		return protobuf.MarshalAnyToProto(&v1types.Metrics{})
 	}
-	return typeurl.MarshalAny(&v2types.Metrics{})
+	return protobuf.MarshalAnyToProto(&v2types.Metrics{})
 }
-- 
2.37.2