|
4 | 4 |
|
5 | 5 | :_mod-docs-content-type: PROCEDURE
|
6 | 6 | [id="nodes-containers-dev-fuse-configuring_{context}"]
|
7 |
| -= Configuring /dev/fuse on unprivileged pods |
| 7 | += Configuring /dev/fuse for unprivileged builds in pods |
8 | 8 |
|
9 |
| -As an alternative to the virtual filesystem, you can configure the `/dev/fuse` device to the `io.kubernetes.cri-o.Devices` annotation to access faster builds within unprivileged pods. Using `/dev/fuse` is secure, efficient, and scalable, and allows unprivileged users to mount an overlay filesystem as if the unprivileged pod was privileged. |
| 9 | +By exposing the `/dev/fuse` device to an unprivileged pod, you grant it the capability to perform Filesystem in Userspace (FUSE) mounts. This is achieved by adding the `io.kubernetes.cri-o.Devices: "/dev/fuse"` annotation to your pod definition. This setup allows an unprivileged user within the pod to use tools like `podman` with storage drivers such as `fuse-overlayfs` by mimicking privileged build capabilities in a secure and efficient manner without granting full privileged access to the pod. |
10 | 10 |
|
11 | 11 | .Procedure
|
12 | 12 |
|
13 |
| -. Create the pod. |
| 13 | +. Define the pod with `/dev/fuse` access: |
14 | 14 | +
|
15 |
| -[source,terminal] |
| 15 | +* Create a YAML file named `fuse-builder-pod.yaml` with the following content: |
| 16 | ++ |
| 17 | +[source,yaml] |
16 | 18 | ----
|
17 |
| -$ oc exec -ti no-priv -- /bin/bash |
| 19 | +apiVersion: v1 |
| 20 | +kind: Pod |
| 21 | +metadata: |
| 22 | + name: fuse-builder-pod |
| 23 | + annotations: |
| 24 | + io.kubernetes.cri-o.Devices: "/dev/fuse" <1> |
| 25 | +spec: |
| 26 | + containers: |
| 27 | + - name: build-container |
| 28 | + image: quay.io/podman/stable <2> |
| 29 | + command: ["/bin/sh", "-c"] |
| 30 | + args: ["echo 'Container is running. Use oc exec to get a shell.'; sleep infinity"] <3> |
| 31 | + securityContext: <4> |
| 32 | + runAsUser: 1000 |
18 | 33 | ----
|
19 | 34 | +
|
| 35 | +<1> The `io.kubernetes.cri-o.Devices: "/dev/fuse"` annotation makes the FUSE device available. |
| 36 | +<2> This annotation specifies a container that uses an image that includes `podman` (for example, `quay.io/podman/stable`). |
| 37 | +<3> This command keeps the container running so you can `exec` into it. |
| 38 | +<4> This annotation specifies a `securityContext` that runs the container as an unprivileged user (for example, `runAsUser: 1000`). |
| 39 | +* |
| 40 | ++ |
| 41 | +[NOTE] |
| 42 | +==== |
| 43 | +Depending on your cluster's Security Context Constraints (SCCs) or other policies, you might need to further adjust the `securityContext` specification, for example, by allowing specific capabilities if `/dev/fuse` alone is not sufficient for `fuse-overlayfs` to operate. |
| 44 | +==== |
| 45 | ++ |
| 46 | +* Create the pod by running the following command: |
| 47 | ++ |
20 | 48 | [source,terminal]
|
21 | 49 | ----
|
22 |
| -$ cat >> Dockerfile <<EOF |
23 |
| -FROM registry.access.redhat.com/ubi9 |
24 |
| -EOF |
| 50 | +$ oc apply -f fuse-builder-pod.yaml |
25 | 51 | ----
|
| 52 | +
|
| 53 | +. Verify that the pod is running: |
26 | 54 | +
|
27 | 55 | [source,terminal]
|
28 | 56 | ----
|
29 |
| -$ podman build . |
| 57 | +$ oc get pods fuse-builder-pod |
30 | 58 | ----
|
31 | 59 |
|
32 |
| -. Implement `/dev/fuse` by adding the `/dev/fuse` device to the `io.kubernetes.cri-o.Devices` annotation. |
| 60 | +. Access the pod and prepare the build environment: |
33 | 61 | +
|
34 |
| -[source,yaml] |
| 62 | +After the `fuse-builder-pod` pod is in the `Running` state, open a shell session into the `build-container` environment: |
| 63 | ++ |
| 64 | +[source,terminal] |
35 | 65 | ----
|
36 |
| -io.kubernetes.cri-o.Devices: "/dev/fuse" |
| 66 | +$ oc exec -ti fuse-builder-pod -- /bin/bash |
37 | 67 | ----
|
38 | 68 | +
|
39 |
| -For example: |
| 69 | +You are now inside the container. Because the default working directory might not be writable by the unprivileged user, change to a writable directory like `/tmp`: |
40 | 70 | +
|
41 |
| -[source,yaml] |
| 71 | +[source,terminal] |
42 | 72 | ----
|
43 |
| -apiVersion: v1 |
44 |
| -kind: Pod |
45 |
| -metadata: |
46 |
| - name: podman-pod |
47 |
| - annotations: |
48 |
| - io.kubernetes.cri-o.Devices: "/dev/fuse" |
| 73 | +$ cd /tmp |
| 74 | +$ pwd |
| 75 | +/tmp |
49 | 76 | ----
|
50 | 77 |
|
51 |
| -. Configure the `/dev/fuse` device in your pod specifications. |
| 78 | +. Create a dockerfile and build an image using Podman: |
52 | 79 | +
|
53 |
| -[source,yaml] |
| 80 | +Inside the pod's shell and within the `/tmp` directory, you can now create a `Dockerfile` and use `podman` to build a container image. If `fuse-overlayfs` is the default or configured storage driver, Podman is able to leverage `fuse-overlayfs` because of the available `/dev/fuse` device. |
| 81 | ++ |
| 82 | +.. Create a sample `Dockerfile`: |
| 83 | ++ |
| 84 | +[source,terminal] |
54 | 85 | ----
|
55 |
| -spec: |
56 |
| - containers: |
57 |
| - - name: podman-container |
58 |
| - image: quay.io/podman/stable |
59 |
| - args: |
60 |
| - - sleep |
61 |
| - - "1000000" |
62 |
| - securityContext: |
63 |
| - runAsUser: 1000 |
| 86 | +$ cat > Dockerfile <<EOF |
| 87 | +FROM registry.access.redhat.com/ubi9/ubi-minimal |
| 88 | +RUN microdnf install -y findutils && microdnf clean all |
| 89 | +RUN echo "This image was built inside a pod with /dev/fuse by user $(id -u)" > /app/build_info.txt |
| 90 | +COPY Dockerfile /app/Dockerfile_copied |
| 91 | +WORKDIR /app |
| 92 | +CMD ["sh", "-c", "cat /app/build_info.txt && echo '--- Copied Dockerfile ---' && cat /app/Dockerfile_copied"] |
| 93 | +EOF |
64 | 94 | ----
|
| 95 | ++ |
| 96 | +.. Build the image using `podman`. The `-t` flag tags the image: |
| 97 | ++ |
| 98 | +[source,terminal] |
| 99 | +---- |
| 100 | +$ podman build -t my-fuse-built-image:latest . |
| 101 | +---- |
| 102 | ++ |
| 103 | +You should see Podman executing the build steps. |
65 | 104 |
|
| 105 | +. Optional: Test the built image: |
| 106 | ++ |
| 107 | +Still inside the `fuse-builder-pod`, you can run a container from the image you just built to test it: |
| 108 | ++ |
| 109 | +[source,terminal] |
| 110 | +---- |
| 111 | +$ podman run --rm my-fuse-built-image:latest |
| 112 | +---- |
| 113 | ++ |
| 114 | +This should output the content of the `/app/build_info.txt` file and the copied Dockerfile. |
66 | 115 |
|
| 116 | +. Exit the pod and clean up: |
| 117 | ++ |
| 118 | +* After you are done, exit the shell session in the pod: |
| 119 | ++ |
| 120 | +[source,terminal] |
| 121 | +---- |
| 122 | +$ exit |
| 123 | +---- |
| 124 | ++ |
| 125 | +* You can then delete the pod if it's no longer needed: |
| 126 | ++ |
| 127 | +[source,terminal] |
| 128 | +---- |
| 129 | +$ oc delete pod fuse-builder-pod |
| 130 | +---- |
| 131 | ++ |
| 132 | +* Remove the local YAML file: |
| 133 | ++ |
| 134 | +[source,terminal] |
| 135 | +---- |
| 136 | +$ rm fuse-builder-pod.yaml |
| 137 | +---- |
0 commit comments