fix: use image digest when starting a container

First of all, it seems to be "right way", as it makes sure the image is
looked up by the digest.

Second, it fixes the case when image is specified with both tag and
digest (which is not supposed to be the correct ref, but it is used
frequently).

Talos since 1.5.0 stores images with the following aliases:

```
gcr.io/etcd-development/etcd:v3.5.9
gcr.io/etcd-development/etcd@sha256:8c956d9b0d39745fa574bb4dbacd362ffdc1109479432f54094859d4cf984b17
ghcr.io/siderolabs/kubelet:v1.28.0
ghcr.io/siderolabs/kubelet@sha256:50710f2cd3328c23f57dfc7fb00940d8cfd402315e33fc7cb8184fc660650a5c
sha256:50710f2cd3328c23f57dfc7fb00940d8cfd402315e33fc7cb8184fc660650a5c
sha256:8c956d9b0d39745fa574bb4dbacd362ffdc1109479432f54094859d4cf984b17
```

This change pulls the digest format (the last in this list) and uses it
to start a container.

Fixes #7640

Signed-off-by: Andrey Smirnov <andrey.smirnov@siderolabs.com>
This commit is contained in:
Andrey Smirnov 2023-08-21 15:45:48 +04:00
parent 175747cea5
commit 574d48e540
No known key found for this signature in database
GPG Key ID: FE042E3D4085A811
2 changed files with 17 additions and 9 deletions

View File

@ -67,6 +67,8 @@ type Etcd struct {
args []string
client *etcd.Client
imgRef string
// if the new member was added as a learner during the service start, its ID is kept here
learnerMemberID uint64
@ -81,18 +83,18 @@ func (e *Etcd) ID(r runtime.Runtime) string {
// PreFunc implements the Service interface.
//
//nolint:gocyclo
func (e *Etcd) PreFunc(ctx context.Context, r runtime.Runtime) (err error) {
if err = os.MkdirAll(constants.EtcdDataPath, 0o700); err != nil {
func (e *Etcd) PreFunc(ctx context.Context, r runtime.Runtime) error {
if err := os.MkdirAll(constants.EtcdDataPath, 0o700); err != nil {
return err
}
// Data path might exist after upgrade from previous version of Talos.
if err = os.Chmod(constants.EtcdDataPath, 0o700); err != nil {
if err := os.Chmod(constants.EtcdDataPath, 0o700); err != nil {
return err
}
// Make sure etcd user can access files in the data directory.
if err = filetree.ChownRecursive(constants.EtcdDataPath, constants.EtcdUserID, constants.EtcdUserID); err != nil {
if err := filetree.ChownRecursive(constants.EtcdDataPath, constants.EtcdUserID, constants.EtcdUserID); err != nil {
return err
}
@ -106,11 +108,13 @@ func (e *Etcd) PreFunc(ctx context.Context, r runtime.Runtime) (err error) {
// Pull the image and unpack it.
containerdctx := namespaces.WithNamespace(ctx, constants.SystemContainerdNamespace)
_, err = image.Pull(containerdctx, r.Config().Machine().Registries(), client, r.Config().Cluster().Etcd().Image(), image.WithSkipIfAlreadyPulled())
img, err := image.Pull(containerdctx, r.Config().Machine().Registries(), client, r.Config().Cluster().Etcd().Image(), image.WithSkipIfAlreadyPulled())
if err != nil {
return fmt.Errorf("failed to pull image %q: %w", r.Config().Cluster().Etcd().Image(), err)
}
e.imgRef = img.Target().Digest.String()
// Clear any previously set learner member ID
e.learnerMemberID = 0
@ -213,7 +217,7 @@ func (e *Etcd) Runner(r runtime.Runtime) (runner.Runner, error) {
&args,
runner.WithLoggingManager(r.Logging()),
runner.WithNamespace(constants.SystemContainerdNamespace),
runner.WithContainerImage(r.Config().Cluster().Etcd().Image()),
runner.WithContainerImage(e.imgRef),
runner.WithEnv(env),
runner.WithOCISpecOpts(
oci.WithDroppedCapabilities(cap.Known()),

View File

@ -40,7 +40,9 @@ var _ system.HealthcheckedService = (*Kubelet)(nil)
// Kubelet implements the Service interface. It serves as the concrete type with
// the required methods.
type Kubelet struct{}
type Kubelet struct {
imgRef string
}
// ID implements the Service interface.
func (k *Kubelet) ID(r runtime.Runtime) string {
@ -66,11 +68,13 @@ func (k *Kubelet) PreFunc(ctx context.Context, r runtime.Runtime) error {
// Pull the image and unpack it.
containerdctx := namespaces.WithNamespace(ctx, constants.SystemContainerdNamespace)
_, err = image.Pull(containerdctx, r.Config().Machine().Registries(), client, spec.Image, image.WithSkipIfAlreadyPulled())
img, err := image.Pull(containerdctx, r.Config().Machine().Registries(), client, spec.Image, image.WithSkipIfAlreadyPulled())
if err != nil {
return err
}
k.imgRef = img.Target().Digest.String()
// Create lifecycle resource to signal that the kubelet is about to start.
err = r.State().V1Alpha2().Resources().Create(ctx, k8s.NewKubeletLifecycle(k8s.NamespaceName, k8s.KubeletLifecycleID))
if err != nil && !state.IsConflictError(err) { // ignore if the lifecycle resource already exists
@ -148,7 +152,7 @@ func (k *Kubelet) Runner(r runtime.Runtime) (runner.Runner, error) {
&args,
runner.WithLoggingManager(r.Logging()),
runner.WithNamespace(constants.SystemContainerdNamespace),
runner.WithContainerImage(spec.Image),
runner.WithContainerImage(k.imgRef),
runner.WithEnv(environment.Get(r.Config())),
runner.WithOCISpecOpts(
containerd.WithRootfsPropagation("shared"),