Sitelet https://github.com/kubernetes/kubernetes/pull/126806
Skip to content

Kubelet should honour the VolumeAttributes which are reported by the volume plugin - #126806

Merged
k8s-ci-robot merged 3 commits into
kubernetes:masterfrom
carlory:fix-image-volume-mount
Nov 5, 2024
Merged

k8s-ci-robot merged 3 commits into
kubernetes:masterfrom
carlory:fix-image-volume-mount

Conversation

@carlory

@carlory carlory commented Aug 20, 2024 •

Copy link
Copy Markdown
Member

What type of PR is this?

/kind bug

What this PR does / why we need it:

pods.yaml

apiVersion: v1
kind: Pod
metadata:
  name: pod1
  namespace: default
spec:
  containers:
  - image: registry.k8s.io/e2e-test-images/echoserver:2.3
    imagePullPolicy: IfNotPresent
    name: test
    volumeMounts:
    - mountPath: /volume
      name: volume
  volumes:
  - image:
      pullPolicy: IfNotPresent
      reference: quay.io/crio/artifact:v1
    name: volume
---
apiVersion: v1
kind: Pod
metadata:
  name: pod2
  namespace: default
spec:
  containers:
  - image: registry.k8s.io/e2e-test-images/echoserver:2.3
    imagePullPolicy: IfNotPresent
    name: test
    volumeMounts:
    - mountPath: /volume
      name: volume
  volumes:
  - image:
      pullPolicy: IfNotPresent
      reference: quay.io/crio/artifact:v1
    name: volume
---
apiVersion: v1
kind: Pod
metadata:
  name: pod3
  namespace: default
spec:
  containers:
  - image: registry.k8s.io/e2e-test-images/echoserver:2.3
    imagePullPolicy: IfNotPresent
    name: test
    volumeMounts:
    - mountPath: /etc/hosts
      name: volume
  volumes:
  - image:
      pullPolicy: IfNotPresent
      reference: quay.io/crio/artifact:v1
    name: volume
---
apiVersion: v1
kind: Pod
metadata:
  name: pod4
  namespace: default
spec:
  containers:
  - image: registry.k8s.io/e2e-test-images/echoserver:2.3
    imagePullPolicy: IfNotPresent
    name: test
    volumeMounts:
    - mountPath: /etc/hosts
      name: volume
  volumes:
  - emptyDir: {}
    name: volume
  • pod1 and pod2 share the same image volume source type and are mounted to /volume in the container.
  • pod3 and pod4 mount the volume to /etc/hosts in the container but use different volume source types.

without this fix

pod3 is running but pod4 has CreateContainerError status.

(base) ➜  kubernetes git:(fix-image-volume-mount) kubectl get po
NAME   READY   STATUS                 RESTARTS   AGE
pod1   1/1     Running                0          29s
pod2   1/1     Running                0          29s
pod3   1/1     Running                0          29s
pod4   0/1     CreateContainerError   0          29s

pod1 mount with rw option

root@crio2-control-plane:/# crictl inspect 5c76497deb40c |  jq .status.mounts[0]
{
  "containerPath": "/volume",
  "gidMappings": [],
  "hostPath": "/var/lib/containers/storage/overlay/82099f56ba7822d8408ac8517b90bde2aa036ac32ee2dd3db810348302edd618/merged",
  "propagation": "PROPAGATION_PRIVATE",
  "readonly": false,
  "recursiveReadOnly": false,
  "selinuxRelabel": false,
  "uidMappings": []
}

root@crio2-control-plane:/# crictl inspect 5c76497deb40c | jq .info.runtimeSpec.mounts[10]
{
  "destination": "/volume",
  "type": "bind",
  "source": "/var/lib/containers/storage/overlay/82099f56ba7822d8408ac8517b90bde2aa036ac32ee2dd3db810348302edd618/merged",
  "options": [
    "rbind",
    "rprivate",
    "rw",
    "bind"
  ]
}

with this fix

pod3 and pod4 has CreateContainerError status.

(base) ➜  kubernetes git:(fix-image-volume-mount) kubectl get po
NAME   READY   STATUS                 RESTARTS   AGE
pod1   1/1     Running                0          44m
pod2   1/1     Running                0          44m
pod3   0/1     CreateContainerError   0          44m
pod4   0/1     CreateContainerError   0          44m

(base) ➜  kubernetes git:(fix-image-volume-mount) kubectl describe po pod3
Events:
  Type     Reason     Age                  From               Message
  ----     ------     ----                 ----               -------
  Normal   Scheduled  51m                  default-scheduler  Successfully assigned default/pod3 to crio-control-plane
  Normal   Pulled     50m (x8 over 51m)    kubelet            Container image "registry.k8s.io/e2e-test-images/echoserver:2.3" already present on machine
  Warning  Failed     50m (x8 over 51m)    kubelet            Error: container create failed: mount `/var/lib/containers/storage/overlay/82099f56ba7822d8408ac8517b90bde2aa036ac32ee2dd3db810348302edd618/merged` to `etc/hosts`: Not a directory
  Normal   Pulled     78s (x229 over 51m)  kubelet            Container image "quay.io/crio/artifact:v1" already present on machine

(base) ➜  kubernetes git:(fix-image-volume-mount) kubectl describe po pod4
Events:
  Type     Reason     Age                  From               Message
  ----     ------     ----                 ----               -------
  Normal   Scheduled  51m                  default-scheduler  Successfully assigned default/pod4 to crio-control-plane
  Warning  Failed     49m (x12 over 51m)   kubelet            Error: container create failed: mount `/var/lib/kubelet/pods/983847e3-109e-4a2e-89f6-5cd0fef3b4cc/volumes/kubernetes.io~empty-dir/volume` to `etc/hosts`: Not a directory
  Normal   Pulled     81s (x233 over 51m)  kubelet            Container image "registry.k8s.io/e2e-test-images/echoserver:2.3" already present on machine

pod1 mount with ro option

(base) ➜  kubernetes git:(fix-image-volume-mount) docker exec -it 92a9726219db bash
root@crio-control-plane:/# crictl inspect 90e489c2aa5e2 | jq .status.mounts[0]
{
  "containerPath": "/volume",
  "gidMappings": [],
  "hostPath": "/var/lib/containers/storage/overlay/82099f56ba7822d8408ac8517b90bde2aa036ac32ee2dd3db810348302edd618/merged",
  "propagation": "PROPAGATION_PRIVATE",
  "readonly": true,
  "recursiveReadOnly": false,
  "selinuxRelabel": false,
  "uidMappings": []
}

root@crio-control-plane:/# crictl inspect 90e489c2aa5e2 | jq .info.runtimeSpec.mounts[10]
{
  "destination": "/volume",
  "type": "bind",
  "source": "/var/lib/containers/storage/overlay/82099f56ba7822d8408ac8517b90bde2aa036ac32ee2dd3db810348302edd618/merged",
  "options": [
    "rbind",
    "rprivate",
    "ro",
    "bind"
  ]
}

Which issue(s) this PR fixes:

Related to kubernetes/enhancements#4639

Special notes for your reviewer:

Does this PR introduce a user-facing change?

1. When the kubelet constructs the cri mounts for the container which references an `image` volume source type, It passes the missing mount attributes to the CRI implementation, including `readOnly`, `propagation`, and `recursiveReadOnly`. When the readOnly field of the containerMount is explicitly set to false, the kubelet will take the `readOnly`as true to the CRI implementation because the image volume plugin requires the mount to be read-only. 
2. Fix a bug where the pod is unexpectedly running when the `image` volume source type is used and mounted to `/etc/hosts` in the container.

Additional documentation e.g., KEPs (Kubernetes Enhancement Proposals), usage docs, etc.:


@k8s-ci-robot k8s-ci-robot added release-note Denotes a PR that will be considered when it comes time to generate release notes. size/L Denotes a PR that changes 100-499 lines, ignoring generated files. kind/bug Categorizes issue or PR as related to a bug. cncf-cla: yes Indicates the PR's author has signed the CNCF CLA. do-not-merge/needs-sig Indicates an issue or PR lacks a `sig/foo` label and requires one. needs-triage Indicates an issue or PR lacks a `triage/foo` label and requires one. labels Aug 20, 2024
@k8s-ci-robot

Copy link
Copy Markdown
Contributor

This issue is currently awaiting triage.

If a SIG or subproject determines this is a relevant issue, they will accept it by applying the triage/accepted label and provide further guidance.

The triage/accepted label can be added by org members by writing /triage accepted in a comment.

Details

Instructions for interacting with me using PR comments are available here. If you have questions or suggestions related to my behavior, please file an issue against the kubernetes-sigs/prow repository.

@k8s-ci-robot k8s-ci-robot added the needs-priority Indicates a PR lacks a `priority/foo` label and requires one. label Aug 20, 2024
@carlory

carlory commented Aug 20, 2024

Copy link
Copy Markdown
Member Author

/hold

@k8s-ci-robot k8s-ci-robot added do-not-merge/hold Indicates that a PR should not merge because someone has issued a /hold command. area/kubelet sig/node Categorizes an issue or PR as relevant to SIG Node. and removed do-not-merge/needs-sig Indicates an issue or PR lacks a `sig/foo` label and requires one. labels Aug 20, 2024
@k8s-ci-robot
k8s-ci-robot requested review from dims and sjenning August 20, 2024 08:51
Comment thread pkg/kubelet/kubelet_pods.go
@carlory

carlory commented Aug 20, 2024

Copy link
Copy Markdown
Member Author

/cc @jsafrane @gnufied @saschagrunert

@saschagrunert

saschagrunert commented Aug 20, 2024 •

Copy link
Copy Markdown
Member

The refCount of the layer is being rapidly increased. What's wrong with my changes?

I tested that locally and every container creation will trigger a new mount, but that's just a counter and not a real system mount. I think that's not a big issue.

Comment thread pkg/kubelet/kubelet_pods.go Outdated
@carlory

carlory commented Aug 20, 2024 •

Copy link
Copy Markdown
Member Author
kubectl create -f pod1.yaml -f pod3.yaml

crio log:

root@crio-control-plane:/run/containers/storage/overlay-layers# cat mountpoints.json | jq .[0]
{
  "id": "82099f56ba7822d8408ac8517b90bde2aa036ac32ee2dd3db810348302edd618",
  "path": "/var/lib/containers/storage/overlay/82099f56ba7822d8408ac8517b90bde2aa036ac32ee2dd3db810348302edd618/merged",
  "count": 620
}
root@crio-control-plane:/run/containers/storage/overlay-layers# journalctl -u crio -e | grep 'Image ref to mount' | wc -l
5
root@crio-control-plane:/run/containers/storage/overlay-layers# journalctl -u crio -e | grep 'Image ID to mount' | wc -l
5

@saschagrunert

This comment was marked as outdated.

@k8s-ci-robot

This comment was marked as outdated.

@saschagrunert

Copy link
Copy Markdown
Member

/test pull-kubernetes-node-crio-cgrpv2-imagevolume-e2e

@saschagrunert

Copy link
Copy Markdown
Member

@carlory we may have to change something SELinux related: https://prow.k8s.io/view/gs/kubernetes-jenkins/pr-logs/pull/126806/pull-kubernetes-node-crio-cgrpv2-imagevolume-e2e/1825835412535382016

waiting:
                message: 'relabel failed /var/lib/containers/storage/overlay/82099f56ba7822d8408ac8517b90bde2aa036ac32ee2dd3db810348302edd618/merged:
                  lsetxattr /var/lib/containers/storage/overlay/82099f56ba7822d8408ac8517b90bde2aa036ac32ee2dd3db810348302edd618/merged/dir:
                  read-only file system'
                reason: CreateContainerError

@carlory
carlory force-pushed the fix-image-volume-mount branch from 331e052 to 6d88f17 Compare August 20, 2024 10:38
vol.SELinuxLabeled = true
relabelVolume = true
}
hostPath, err := volumeutil.GetPath(vol.Mounter)

Copy link
Copy Markdown
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

I am concerned of moving and changing so much code that is not under the feature gate. Was it added alongside the feature?

Ideally we want to minimize the number of potential regressions and keep existing codepaths as close to what they were without the feature gate as possible

Copy link
Copy Markdown
Member Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

I am concerned of moving and changing so much code that is not under the feature gate. Was it added alongside the feature?

It just adds a new conditon check for the previous code. It doesn't change the code itself. I add the feature-gate check in line 289. If the feature-gate is disabled, the image will be nil and old logic will be executed. @SergeyKanzhelev

Name: mount.Name,
ContainerPath: containerPath,
HostPath: hostPath,
Image: image,

Copy link
Copy Markdown
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

I wonder how it worked without the image before? What is the image field is being used for if it was not passed here before and nothing broke?

@carlory carlory Sep 14, 2024 •

Copy link
Copy Markdown
Member Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

It aims to add all missing mount information to the runtime when the volume source is image and let them decide.

Copy link
Copy Markdown
Member Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

@SergeyKanzhelev some volume attributes reported by the image volume plugin, i.e. relabel, read-only, etc., aren't sent to the implementation of CRI runtime in previous kubelet implementation.

func makeMounts(pod *v1.Pod, podDir string, container *v1.Container, hostName, hostDomain string, podIPs []string, podVolumes kubecontainer.VolumeMap, hu hostutil.HostUtils, subpather subpath.Interface, expandEnvs []kubecontainer.EnvVar, supportsRRO bool, imageVolumes kubecontainer.ImageVolumes) ([]kubecontainer.Mount, func(), error) {
	mountEtcHostsFile := shouldMountHostsFile(pod, podIPs)
	klog.V(3).InfoS("Creating hosts mount for container", "pod", klog.KObj(pod), "containerName", container.Name, "podIPs", podIPs, "path", mountEtcHostsFile)
	mounts := []kubecontainer.Mount{}
	var cleanupAction func()
	for i, mount := range container.VolumeMounts {
		// Check if the mount is referencing an OCI volume
		if imageVolumes != nil && utilfeature.DefaultFeatureGate.Enabled(features.ImageVolume) {
			if image, ok := imageVolumes[mount.Name]; ok {
				mounts = append(mounts, kubecontainer.Mount{
					Name:          mount.Name,
					ContainerPath: mount.MountPath,
					Image:         image,
				})
				continue
			}
		}
                 ...skipped..
		mounts = append(mounts, kubecontainer.Mount{
			Name:              mount.Name,
			ContainerPath:     containerPath,
			HostPath:          hostPath,
			ReadOnly:          mount.ReadOnly || mustMountRO,
			RecursiveReadOnly: rro,
			SELinuxRelabel:    relabelVolume,
			Propagation:       propagation,
		})
	}
                 ...skipped..
	return mounts, cleanupAction, nil

What's the result? Please see the without this fix section in my PR's description.

@gnufied

gnufied commented Sep 13, 2024 •

Copy link
Copy Markdown
Member

After bind-mount stuff was fixed for selinux stuff - cri-o/cri-o#8521, what is the new behaviour? @carlory can you please confirm without your change and with your change?

@carlory

carlory commented Sep 14, 2024 •

Copy link
Copy Markdown
Member Author

After bind-mount stuff was fixed for selinux stuff - cri-o/cri-o#8521, what is the new behaviour? @carlory can you please confirm without your change and with your change?

@gnufied
This PR is not related to selinux issue, but that is detected by this PR when running the pull-kubernetes-node-crio-cgrpv2-imagevolume-e2e job, in order to make the job pass, the PR changes the volume attributes reported by the image volume plugin, see #126806 (comment) for more details. At that time, we think the issue is a known limitation for all volume plugins, so we open a PR for the website to document it. We also asked about the limitation with the sig-storage in the community meeting but got a different answer. Thanks a lot for all the help from the community. @saschagrunert raised a PR to fix it in the CRI-O repo and kubernetes/website#47588 was closed, so no new behavior is introduced and #126991 added a new test case for node e2e tests to verify the fix. The result is passed.

since cri-o/cri-o#8521 is merged, the root cause is fixed, so it won't occur again with or without this PR. Why not revert selinux configuration in this PR, please see #126806 (comment).

This PR mainly aims to add all missing mount information to the runtime and let them decide.

@carlory

carlory commented Sep 14, 2024

Copy link
Copy Markdown
Member Author

How any of those changes tested? Why no existing tests broke? Can you please add tests demonstrating the wrong behavior and the fix

No existing test is broken. I am adding new test.

@carlory

carlory commented Sep 14, 2024

Copy link
Copy Markdown
Member Author

for release notes, I would suggest to rephrase the first one from the SHOULD statement to the description on what was changed

updated.

@carlory
carlory force-pushed the fix-image-volume-mount branch from 1a81cfa to d05abe1 Compare September 14, 2024 09:36
@carlory
carlory force-pushed the fix-image-volume-mount branch from d05abe1 to 69d6e0e Compare November 5, 2024 06:37
@carlory
carlory force-pushed the fix-image-volume-mount branch from 69d6e0e to 2529d7d Compare November 5, 2024 07:09
@SergeyKanzhelev

Copy link
Copy Markdown
Member

lost track of this PR. Now it only have test files in it. Perhaps a wrong force push?

@carlory

carlory commented Nov 5, 2024 •

Copy link
Copy Markdown
Member Author

I am concerned of moving and changing so much code that is not under the feature gate. Was it added alongside the feature?

Ideally we want to minimize the number of potential regressions and keep existing codepaths as close to what they were without the feature gate as possible

Copid from #126806 (comment)

In order to make the new test to check the new feature without the fix, I pushed the first commit to the same PR.

@SergeyKanzhelev I'm trying to update the makeMounts function to reduce the number of changed lines. I will push the second commit to the same PR once I achieve the above goal.

Edit:

New tests fail as expected without the fix.

https://prow.k8s.io/view/gs/kubernetes-ci-logs/pr-logs/pull/126806/pull-kubernetes-unit/1853696165627826176

@carlory

carlory commented Nov 5, 2024 •

Copy link
Copy Markdown
Member Author

/cc @saschagrunert @SergeyKanzhelev @gnufied

Please review it again.

Edit: I'm trying to reduce the number of changed lines but fail to achieve that. I give up and revert it to the previous state.

It just adds a new conditon check for the previous code. It doesn't change the code itself. I add the feature-gate check in line 304. If the feature-gate is disabled, the image will be nil and old logic will be executed.

… references an `image` volume source type, It passes the missing mount attributes to the CRI implementation, including `readOnly`, `propagation`, and `recursiveReadOnly`. When the readOnly field of the containerMount is explicitly set to false, the kubelet will take the `readOnly`as true to the CRI implementation because the image volume plugin requires the mount to be read-only.

2. Fix a bug where the pod is unexpectedly running when the `image` volume source type is used and mounted to `/etc/hosts` in the container.
@carlory
carlory force-pushed the fix-image-volume-mount branch from a79af52 to b6c9c2d Compare November 5, 2024 11:47

@SergeyKanzhelev SergeyKanzhelev left a comment

Copy link
Copy Markdown
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

/lgtm
/approve

thank you for resolving all comments

@k8s-ci-robot k8s-ci-robot added the lgtm "Looks good to me", indicates that a PR is ready to be merged. label Nov 5, 2024
@k8s-ci-robot

Copy link
Copy Markdown
Contributor

LGTM label has been added.

DetailsGit tree hash: 6e55785d79059f36a6f30a4b66504a8ec513e314

@k8s-ci-robot

Copy link
Copy Markdown
Contributor

[APPROVALNOTIFIER] This PR is APPROVED

This pull-request has been approved by: carlory, saschagrunert, SergeyKanzhelev

The full list of commands accepted by this bot can be found here.

The pull request process is described here

Details Needs approval from an approver in each of these files:

Approvers can indicate their approval by writing /approve in a comment
Approvers can cancel approval by writing /approve cancel in a comment

@k8s-ci-robot k8s-ci-robot added the approved Indicates a PR has been approved by an approver from all required OWNERS files. label Nov 5, 2024
@k8s-ci-robot
k8s-ci-robot merged commit b5e6456 into kubernetes:master Nov 5, 2024
@k8s-ci-robot k8s-ci-robot added this to the v1.32 milestone Nov 5, 2024
@carlory
carlory deleted the fix-image-volume-mount branch November 6, 2024 02:05
mhan8796 pushed a commit to mhan8796/kubernetes that referenced this pull request Jun 27, 2026
Kubelet should honour the VolumeAttributes which are reported by the volume plugin
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Labels

approved Indicates a PR has been approved by an approver from all required OWNERS files. area/kubelet cncf-cla: yes Indicates the PR's author has signed the CNCF CLA. kind/bug Categorizes issue or PR as related to a bug. lgtm "Looks good to me", indicates that a PR is ready to be merged. needs-priority Indicates a PR lacks a `priority/foo` label and requires one. needs-triage Indicates an issue or PR lacks a `triage/foo` label and requires one. release-note Denotes a PR that will be considered when it comes time to generate release notes. sig/node Categorizes an issue or PR as relevant to SIG Node. sig/storage Categorizes an issue or PR as relevant to SIG Storage. size/L Denotes a PR that changes 100-499 lines, ignoring generated files.

Projects

Development

Successfully merging this pull request may close these issues.

5 participants