diff --git a/Dockerfile b/Dockerfile index 6775afc65254..50a21cdb2d57 100644 --- a/Dockerfile +++ b/Dockerfile @@ -162,8 +162,8 @@ FROM scratch AS cni-plugins-export-squashed COPY --from=cni-plugins-export / / FROM --platform=$BUILDPLATFORM alpine:${ALPINE_VERSION} AS binfmt-filter -# built from https://github.com/tonistiigi/binfmt/releases/tag/buildkit%2Fv9.2.0-50 -COPY --link --from=tonistiigi/binfmt:buildkit-v9.2.0-50@sha256:ff21b00e7238dce3bbd74fbe25591f7213837a77861b47b2df5e019540ec33fa / /out/ +# built from https://github.com/tonistiigi/binfmt/releases/tag/buildkit%2Fv9.2.2-54 +COPY --link --from=tonistiigi/binfmt:buildkit-v9.2.2-54@sha256:e60fbf01e26c75efa816224f4de31c2ef63c5486b20c3e8fa1e5da2aff368ba9 / /out/ WORKDIR /out/ RUN rm buildkit-qemu-loongarch64 buildkit-qemu-mips64 buildkit-qemu-mips64el diff --git a/cmd/buildkitd/main.go b/cmd/buildkitd/main.go index 364252a59b34..8b6e0b3653c8 100644 --- a/cmd/buildkitd/main.go +++ b/cmd/buildkitd/main.go @@ -1067,6 +1067,13 @@ func getCDIManager(cfg config.CDIConfig) (*cdidevices.Manager, error) { if err := cdiCache.Refresh(); err != nil { return nil, err } + if errs := cdiCache.GetErrors(); len(errs) > 0 { + for dir, errs := range errs { + for _, err := range errs { + bklog.L.Warnf("CDI setup error %v: %+v", dir, err) + } + } + } return cdiCache, nil }() if err != nil { diff --git a/docs/rootless.md b/docs/rootless.md index b2a05883e20e..aafbdf52d1ad 100644 --- a/docs/rootless.md +++ b/docs/rootless.md @@ -12,18 +12,19 @@ Rootless mode allows running BuildKit daemon as a non-root user. [RootlessKit](https://github.com/rootless-containers/rootlesskit/) needs to be installed. -```console -$ rootlesskit buildkitd +```bash +rootlesskit buildkitd ``` -```console -$ buildctl --addr unix:///run/user/$UID/buildkit/buildkitd.sock build ... +```bash +buildctl --addr unix:///run/user/$UID/buildkit/buildkitd.sock build ... ``` -To isolate BuildKit daemon's network namespace from the host (recommended): -```console -$ rootlesskit --net=slirp4netns --copy-up=/etc --disable-host-loopback buildkitd -``` +> [!TIP] +> To isolate BuildKit daemon's network namespace from the host (recommended): +> ```bash +> rootlesskit --net=slirp4netns --copy-up=/etc --disable-host-loopback buildkitd +> ``` ## Running BuildKit in Rootless mode (containerd worker) @@ -31,15 +32,28 @@ $ rootlesskit --net=slirp4netns --copy-up=/etc --disable-host-loopback buildkitd Run containerd in rootless mode using rootlesskit following [containerd's document](https://github.com/containerd/containerd/blob/main/docs/rootless.md). +```bash +containerd-rootless.sh + +CONTAINERD_NAMESPACE=default containerd-rootless-setuptool.sh install-buildkit-containerd ``` -$ containerd-rootless.sh -``` -Then let buildkitd join the same namespace as containerd. +
+Advanced guide + +

+ +Alternatively, you can specify the full command line flags as follows: +```bash +containerd-rootless.sh --config /path/to/config.toml + +containerd-rootless-setuptool.sh nsenter -- buildkitd --oci-worker=false --containerd-worker=true ``` -$ containerd-rootless-setuptool.sh nsenter -- buildkitd --oci-worker=false --containerd-worker=true --containerd-worker-snapshotter=native -``` + +

+ +
## Containerized deployment @@ -48,36 +62,45 @@ See [`../examples/kubernetes`](../examples/kubernetes). ### Docker -```console -$ docker run \ +```bash +docker run \ --name buildkitd \ -d \ --security-opt seccomp=unconfined \ --security-opt apparmor=unconfined \ - --device /dev/fuse \ - moby/buildkit:rootless --oci-worker-no-process-sandbox -$ buildctl --addr docker-container://buildkitd build ... -``` + --security-opt systempaths=unconfined \ + moby/buildkit:rootless -If you don't mind using `--privileged` (almost safe for rootless), the `docker run` flags can be shorten as follows: - -```console -$ docker run --name buildkitd -d --privileged moby/buildkit:rootless +buildctl --addr docker-container://buildkitd build ... ``` -#### About `--device /dev/fuse` -Adding `--device /dev/fuse` to the `docker run` arguments is required only if you want to use `fuse-overlayfs` snapshotter. +> [!TIP] +> If you don't mind using `--privileged` (almost safe for rootless), the `docker run` flags can be shorten as follows: +> +> ```bash +> docker run --name buildkitd -d --privileged moby/buildkit:rootless +> ``` -#### About `--oci-worker-no-process-sandbox` +Justification of the `--security-opt` flags: -By adding `--oci-worker-no-process-sandbox` to the `buildkitd` arguments, BuildKit can be executed in a container without adding `--privileged` to `docker run` arguments. -However, you still need to pass `--security-opt seccomp=unconfined --security-opt apparmor=unconfined` to `docker run`. +* `seccomp=unconfined`: For allowing several syscalls such as `unshare` (used by runc) and `mount` (used by snapshotters, etc). -Note that `--oci-worker-no-process-sandbox` allows build executor containers to `kill` (and potentially `ptrace` depending on the seccomp configuration) an arbitrary process in the BuildKit daemon container. +* `apparmor=unconfined`: For allowing mounting filesystems, etc. + This flag is not needed when the host operating system does not use AppArmor. -To allow running rootless `buildkitd` without `--oci-worker-no-process-sandbox`, run `docker run` with `--security-opt systempaths=unconfined`. (For Kubernetes, set `securityContext.procMount` to `Unmasked`.) +* `systempaths=unconfined`: For disabling the masks for the `/proc` mount in the container, so that each of `ExecOp` + (corresponds to a `RUN` instruction in Dockerfile) can have a dedicated `/proc` filesystem. + `systempaths=unconfined` potentially allows reading and writing dangerous kernel files from a container, but it is safe when you are running `buildkitd` as non-root. -The `--security-opt systempaths=unconfined` flag disables the masks for the `/proc` mount in the container and potentially allows reading and writing dangerous kernel files, but it is safe when you are running `buildkitd` as non-root. +> [!TIP] +> Instead of `--security-opt systempaths=unconfined`, `buildkitd` can be also executed with `--oci-worker-no-process-sandbox` (flag of `buildkitd`, not `docker`) +> to avoid creating a new PID namespace and mounting a new `/proc` for it. +> +> Using `--oci-worker-no-process-sandbox` is discouraged, as it cannot terminate processes that did not exit during an `ExecOp`. +> Also, `--oci-worker-no-process-sandbox` allows `ExecOp` containers to `kill` (and potentially `ptrace` depending on the seccomp configuration) an arbitrary process in the BuildKit daemon container. +> +> Despite these caveats, the [Kubernetes examples](../examples/kubernetes) uses `--oci-worker-no-process-sandbox`, as Kubernetes lacks the equivalent of `systempaths=unconfined`. +> (`securityContext.procMount=Unmasked` is similar, but different in the sense that it depends on `hostUsers: false`) ### Change UID/GID @@ -90,7 +113,7 @@ Actual ID (shown in the host and the BuildKit daemon container)| Mapped ID (show ... | ... 165535 | 65536 -``` +```console $ docker exec buildkitd id uid=1000(user) gid=1000(user) $ docker exec buildkitd ps aux @@ -99,15 +122,16 @@ PID USER TIME COMMAND 13 user 0:00 /proc/self/exe buildkitd --addr tcp://0.0.0.0:1234 21 user 0:00 buildkitd --addr tcp://0.0.0.0:1234 29 user 0:00 ps aux + $ docker exec cat /etc/subuid user:100000:65536 ``` To change the UID/GID configuration, you need to modify and build the BuildKit image manually. -``` -$ vi Dockerfile -$ make images -$ docker run ... moby/buildkit:local-rootless ... +```bash +vi Dockerfile +make images +docker run ... moby/buildkit:local-rootless ... ``` ## Troubleshooting @@ -120,7 +144,9 @@ $ rootlesskit buildkitd --oci-worker-snapshotter=fuse-overlayfs ``` ### Error related to `fuse-overlayfs` -Try running `buildkitd` with `--oci-worker-snapshotter=native`: +Run `docker run` with `--device /dev/fuse`. + +Also try running `buildkitd` with `--oci-worker-snapshotter=native`: ```console $ rootlesskit buildkitd --oci-worker-snapshotter=native @@ -137,12 +163,19 @@ Run `sysctl -w user.max_user_namespaces=N` (N=positive integer, like 63359) on t See [`../examples/kubernetes/sysctl-userns.privileged.yaml`](../examples/kubernetes/sysctl-userns.privileged.yaml). +### Error `fork/exec /proc/self/exe: permission denied` with `This error might have happened because /proc/sys/kernel/apparmor_restrict_unprivileged_userns is set to 1` +Add `kernel.apparmor_restrict_unprivileged_userns=0` to `/etc/sysctl.conf` (or `/etc/sysctl.d`) and run `sudo sysctl -p`. + ### Error `mount proc:/proc (via /proc/self/fd/6), flags: 0xe: operation not permitted` -This error is known to happen when BuildKit is executed in a container without the `--oci-worker-no-sandbox` flag. -Make sure that `--oci-worker-no-process-sandbox` is specified (See [below](#docker)). +This error is known to happen when BuildKit is executed in a container without the `--security-opt systempaths=unconfined` flag. +Make sure to specify it (See [above](#docker)). ## Distribution-specific hint Using Ubuntu kernel is recommended. + +### Ubuntu, 24.04 or later +Add `kernel.apparmor_restrict_unprivileged_userns=0` to `/etc/sysctl.conf` (or `/etc/sysctl.d`) and run `sudo sysctl -p`. + ### Container-Optimized OS from Google Make sure to have an `emptyDir` volume below: ```yaml diff --git a/examples/kubernetes/README.md b/examples/kubernetes/README.md index c8973dc5645d..4d263d16c2eb 100644 --- a/examples/kubernetes/README.md +++ b/examples/kubernetes/README.md @@ -6,16 +6,26 @@ This directory contains Kubernetes manifests for `Pod`, `Deployment` (with `Serv * `StateFulset`: good for client-side load balancing, without registry-side cache * `Job`: good if you don't want to have daemon pods -Using Rootless mode (`*.rootless.yaml`) is recommended because Rootless mode image is executed as non-root user (UID 1000) and doesn't need `securityContext.privileged`. -See [`../../docs/rootless.md`](../../docs/rootless.md). +## Variants -See also ["Building Images Efficiently And Securely On Kubernetes With BuildKit" (KubeCon EU 2019)](https://kccnceu19.sched.com/event/MPX5). +- `*.privileged.yaml`: Launches the Pod as the fully privileged root user. +- `*.rootless.yaml`: Launches the Pod as a non-root user, whose UID is 1000. +- `*.userns.yaml`: Launches the Pod as a non-root user. The UID is determined by kubelet. + Needs kubelet and kube-apiserver to be reconfigured to enable the + [`UserNamespacesSupport`](https://kubernetes.io/docs/tasks/configure-pod-container/user-namespaces/) feature gate. + +It is recommended to use `*.rootless.yaml` to minimize the chance of container breakout attacks. + +See also: +- [`../../docs/rootless.md`](../../docs/rootless.md). +- ["Building Images Efficiently And Securely On Kubernetes With BuildKit" (KubeCon EU 2019)](https://kccnceu19.sched.com/event/MPX5). ## `Pod` -```console -$ kubectl apply -f pod.rootless.yaml -$ buildctl \ +```bash +kubectl apply -f pod.rootless.yaml + +buildctl \ --addr kube-pod://buildkitd \ build --frontend dockerfile.v0 --local context=/path/to/dir --local dockerfile=/path/to/dir ``` @@ -29,25 +39,27 @@ If rootless mode doesn't work, try `pod.privileged.yaml`. Setting up mTLS is highly recommended. `./create-certs.sh SAN [SAN...]` can be used for creating certificates. -```console -$ ./create-certs.sh 127.0.0.1 +```bash +./create-certs.sh 127.0.0.1 ``` The daemon certificates is created as `Secret` manifest named `buildkit-daemon-certs`. -```console -$ kubectl apply -f .certs/buildkit-daemon-certs.yaml +```bash +kubectl apply -f .certs/buildkit-daemon-certs.yaml ``` Apply the `Deployment` and `Service` manifest: -```console -$ kubectl apply -f deployment+service.rootless.yaml -$ kubectl scale --replicas=10 deployment/buildkitd +```bash +kubectl apply -f deployment+service.rootless.yaml + +kubectl scale --replicas=10 deployment/buildkitd ``` Run `buildctl` with TLS client certificates: -```console -$ kubectl port-forward service/buildkitd 1234 -$ buildctl \ +```bash +kubectl port-forward service/buildkitd 1234 + +buildctl \ --addr tcp://127.0.0.1:1234 \ --tlscacert .certs/client/ca.pem \ --tlscert .certs/client/cert.pem \ @@ -58,10 +70,10 @@ $ buildctl \ ## `StatefulSet` `StatefulSet` is useful for consistent hash mode. -```console -$ kubectl apply -f statefulset.rootless.yaml -$ kubectl scale --replicas=10 statefulset/buildkitd -$ buildctl \ +```bash +kubectl apply -f statefulset.rootless.yaml +kubectl scale --replicas=10 statefulset/buildkitd +buildctl \ --addr kube-pod://buildkitd-4 \ build --frontend dockerfile.v0 --local context=/path/to/dir --local dockerfile=/path/to/dir ``` @@ -70,8 +82,8 @@ See [`./consistenthash`](./consistenthash) for how to use consistent hashing. ## `Job` -```console -$ kubectl apply -f job.rootless.yaml +```bash +kubectl apply -f job.rootless.yaml ``` To push the image to the registry, you also need to mount `~/.docker/config.json` diff --git a/examples/kubernetes/deployment+service.rootless.yaml b/examples/kubernetes/deployment+service.rootless.yaml index 0b554096fde6..c82ff9820a3f 100644 --- a/examples/kubernetes/deployment+service.rootless.yaml +++ b/examples/kubernetes/deployment+service.rootless.yaml @@ -13,8 +13,6 @@ spec: metadata: labels: app: buildkitd - annotations: - container.apparmor.security.beta.kubernetes.io/buildkitd: unconfined # see buildkit/docs/rootless.md for caveats of rootless mode spec: containers: @@ -54,6 +52,9 @@ spec: # Needs Kubernetes >= 1.19 seccompProfile: type: Unconfined + # Needs Kubernetes >= 1.30 + appArmorProfile: + type: Unconfined # To change UID/GID, you need to rebuild the image runAsUser: 1000 runAsGroup: 1000 diff --git a/examples/kubernetes/deployment+service.userns.yaml b/examples/kubernetes/deployment+service.userns.yaml new file mode 100644 index 000000000000..acf19937ef4d --- /dev/null +++ b/examples/kubernetes/deployment+service.userns.yaml @@ -0,0 +1,77 @@ +# Depends on feature gate UserNamespacesSupport +apiVersion: apps/v1 +kind: Deployment +metadata: + labels: + app: buildkitd + name: buildkitd +spec: + replicas: 1 + selector: + matchLabels: + app: buildkitd + template: + metadata: + labels: + app: buildkitd + spec: + hostUsers: false + containers: + - name: buildkitd + image: moby/buildkit:master + args: + - --addr + - unix:///run/buildkit/buildkitd.sock + - --addr + - tcp://0.0.0.0:1234 + - --tlscacert + - /certs/ca.pem + - --tlscert + - /certs/cert.pem + - --tlskey + - /certs/key.pem + # the probe below will only work after Release v0.6.3 + readinessProbe: + exec: + command: + - buildctl + - debug + - workers + initialDelaySeconds: 5 + periodSeconds: 30 + # the probe below will only work after Release v0.6.3 + livenessProbe: + exec: + command: + - buildctl + - debug + - workers + initialDelaySeconds: 5 + periodSeconds: 30 + securityContext: + # Not really privileged + privileged: true + ports: + - containerPort: 1234 + volumeMounts: + - name: certs + readOnly: true + mountPath: /certs + volumes: + # buildkit-daemon-certs must contain ca.pem, cert.pem, and key.pem + - name: certs + secret: + secretName: buildkit-daemon-certs +--- +apiVersion: v1 +kind: Service +metadata: + labels: + app: buildkitd + name: buildkitd +spec: + ports: + - port: 1234 + protocol: TCP + selector: + app: buildkitd diff --git a/examples/kubernetes/job.privileged.yaml b/examples/kubernetes/job.privileged.yaml index 352180efab57..472fc0d3516f 100644 --- a/examples/kubernetes/job.privileged.yaml +++ b/examples/kubernetes/job.privileged.yaml @@ -8,11 +8,11 @@ spec: restartPolicy: Never initContainers: - name: prepare - image: alpine:3.10 + image: busybox command: - sh - -c - - "echo FROM hello-world > /workspace/Dockerfile" + - "echo -e 'FROM alpine\nRUN apk add gcc\n' > /workspace/Dockerfile" volumeMounts: - name: workspace mountPath: /workspace diff --git a/examples/kubernetes/job.rootless.yaml b/examples/kubernetes/job.rootless.yaml index 06e608c6ab35..a3904f8d659e 100644 --- a/examples/kubernetes/job.rootless.yaml +++ b/examples/kubernetes/job.rootless.yaml @@ -4,19 +4,16 @@ metadata: name: buildkit spec: template: - metadata: - annotations: - container.apparmor.security.beta.kubernetes.io/buildkit: unconfined # see buildkit/docs/rootless.md for caveats of rootless mode spec: restartPolicy: Never initContainers: - name: prepare - image: alpine:3.10 + image: busybox command: - sh - -c - - "echo FROM hello-world > /workspace/Dockerfile" + - "echo -e 'FROM alpine\nRUN apk add gcc\n' > /workspace/Dockerfile" securityContext: runAsUser: 1000 runAsGroup: 1000 @@ -45,6 +42,9 @@ spec: # Needs Kubernetes >= 1.19 seccompProfile: type: Unconfined + # Needs Kubernetes >= 1.30 + appArmorProfile: + type: Unconfined # To change UID/GID, you need to rebuild the image runAsUser: 1000 runAsGroup: 1000 diff --git a/examples/kubernetes/job.userns.yaml b/examples/kubernetes/job.userns.yaml new file mode 100644 index 000000000000..9305bce14073 --- /dev/null +++ b/examples/kubernetes/job.userns.yaml @@ -0,0 +1,47 @@ +# Depends on feature gate UserNamespacesSupport +apiVersion: batch/v1 +kind: Job +metadata: + name: buildkit +spec: + template: + spec: + hostUsers: false + restartPolicy: Never + initContainers: + - name: prepare + image: busybox + command: + - sh + - -c + - "echo -e 'FROM alpine\nRUN apk add gcc\n' > /workspace/Dockerfile" + volumeMounts: + - name: workspace + mountPath: /workspace + containers: + - name: buildkit + image: moby/buildkit:master + command: + - buildctl-daemonless.sh + args: + - build + - --frontend + - dockerfile.v0 + - --local + - context=/workspace + - --local + - dockerfile=/workspace + # To push the image to a registry, add + # `--output type=image,name=docker.io/username/image,push=true` + securityContext: + # Not really privileged + privileged: true + volumeMounts: + - name: workspace + readOnly: true + mountPath: /workspace + # To push the image, you also need to create `~/.docker/config.json` secret + # and set $DOCKER_CONFIG to `/path/to/.docker` directory. + volumes: + - name: workspace + emptyDir: {} diff --git a/examples/kubernetes/pod.rootless.yaml b/examples/kubernetes/pod.rootless.yaml index 130ea43633fe..4f9864594b37 100644 --- a/examples/kubernetes/pod.rootless.yaml +++ b/examples/kubernetes/pod.rootless.yaml @@ -2,8 +2,6 @@ apiVersion: v1 kind: Pod metadata: name: buildkitd - annotations: - container.apparmor.security.beta.kubernetes.io/buildkitd: unconfined # see buildkit/docs/rootless.md for caveats of rootless mode spec: containers: @@ -31,6 +29,9 @@ spec: # Needs Kubernetes >= 1.19 seccompProfile: type: Unconfined + # Needs Kubernetes >= 1.30 + appArmorProfile: + type: Unconfined # To change UID/GID, you need to rebuild the image runAsUser: 1000 runAsGroup: 1000 diff --git a/examples/kubernetes/pod.userns.yaml b/examples/kubernetes/pod.userns.yaml new file mode 100644 index 000000000000..085c3cde0ee9 --- /dev/null +++ b/examples/kubernetes/pod.userns.yaml @@ -0,0 +1,29 @@ +# Depends on feature gate UserNamespacesSupport +apiVersion: v1 +kind: Pod +metadata: + name: buildkitd +spec: + hostUsers: false + containers: + - name: buildkitd + image: moby/buildkit:master + readinessProbe: + exec: + command: + - buildctl + - debug + - workers + initialDelaySeconds: 5 + periodSeconds: 30 + livenessProbe: + exec: + command: + - buildctl + - debug + - workers + initialDelaySeconds: 5 + periodSeconds: 30 + securityContext: + # Not really privileged + privileged: true diff --git a/examples/kubernetes/statefulset.rootless.yaml b/examples/kubernetes/statefulset.rootless.yaml index 0533d2a1004f..caf7dde3cc2b 100644 --- a/examples/kubernetes/statefulset.rootless.yaml +++ b/examples/kubernetes/statefulset.rootless.yaml @@ -15,8 +15,6 @@ spec: metadata: labels: app: buildkitd - annotations: - container.apparmor.security.beta.kubernetes.io/buildkitd: unconfined # see buildkit/docs/rootless.md for caveats of rootless mode spec: containers: @@ -44,6 +42,9 @@ spec: # Needs Kubernetes >= 1.19 seccompProfile: type: Unconfined + # Needs Kubernetes >= 1.30 + appArmorProfile: + type: Unconfined # To change UID/GID, you need to rebuild the image runAsUser: 1000 runAsGroup: 1000 diff --git a/examples/kubernetes/statefulset.userns.yaml b/examples/kubernetes/statefulset.userns.yaml new file mode 100644 index 000000000000..98af0aad9ef3 --- /dev/null +++ b/examples/kubernetes/statefulset.userns.yaml @@ -0,0 +1,42 @@ +# Depends on feature gate UserNamespacesSupport +apiVersion: apps/v1 +kind: StatefulSet +metadata: + labels: + app: buildkitd + name: buildkitd +spec: + serviceName: buildkitd + podManagementPolicy: Parallel + replicas: 1 + selector: + matchLabels: + app: buildkitd + template: + metadata: + labels: + app: buildkitd + spec: + hostUsers: false + containers: + - name: buildkitd + image: moby/buildkit:master + readinessProbe: + exec: + command: + - buildctl + - debug + - workers + initialDelaySeconds: 5 + periodSeconds: 30 + livenessProbe: + exec: + command: + - buildctl + - debug + - workers + initialDelaySeconds: 5 + periodSeconds: 30 + securityContext: + # Not really privileged + privileged: true diff --git a/frontend/dockerfile/dockerfile2llb/convert.go b/frontend/dockerfile/dockerfile2llb/convert.go index f44866839341..77c91c15d336 100644 --- a/frontend/dockerfile/dockerfile2llb/convert.go +++ b/frontend/dockerfile/dockerfile2llb/convert.go @@ -815,6 +815,7 @@ func toDispatchState(ctx context.Context, dt []byte, opt ConvertOpt) (*dispatchS target.image.OSFeatures = append([]string{}, platformOpt.targetPlatform.OSFeatures...) } } + target.image.Platform = platforms.Normalize(target.image.Platform) return target, nil } diff --git a/go.mod b/go.mod index fe5a805c6cca..dd696567a3cb 100644 --- a/go.mod +++ b/go.mod @@ -17,7 +17,7 @@ require ( github.com/aws/aws-sdk-go-v2/service/s3 v1.58.2 github.com/containerd/console v1.0.4 github.com/containerd/containerd/api v1.8.0 - github.com/containerd/containerd/v2 v2.0.2 + github.com/containerd/containerd/v2 v2.0.3 github.com/containerd/continuity v0.4.5 github.com/containerd/errdefs v1.0.0 github.com/containerd/fuse-overlayfs-snapshotter/v2 v2.1.1 @@ -73,7 +73,7 @@ require ( github.com/stretchr/testify v1.10.0 github.com/tonistiigi/dchapes-mode v0.0.0-20241001053921-ca0759fec205 github.com/tonistiigi/fsutil v0.0.0-20250113203817-b14e27f4135a - github.com/tonistiigi/go-actions-cache v0.0.0-20250219102945-1a5174abd055 + github.com/tonistiigi/go-actions-cache v0.0.0-20250228231703-3e9a6642607f github.com/tonistiigi/go-archvariant v1.0.0 github.com/tonistiigi/go-csvvalue v0.0.0-20240710180619-ddb21b71c0b4 github.com/tonistiigi/units v0.0.0-20180711220420-6950e57a87ea @@ -108,7 +108,7 @@ require ( google.golang.org/grpc/cmd/protoc-gen-go-grpc v1.5.1 google.golang.org/protobuf v1.35.2 kernel.org/pub/linux/libs/security/libcap/cap v1.2.73 - tags.cncf.io/container-device-interface v0.8.0 + tags.cncf.io/container-device-interface v0.8.1 ) require ( diff --git a/go.sum b/go.sum index ce10e2f751c0..fdca30d64082 100644 --- a/go.sum +++ b/go.sum @@ -97,8 +97,8 @@ github.com/containerd/console v1.0.4 h1:F2g4+oChYvBTsASRTz8NP6iIAi97J3TtSAsLbIFn github.com/containerd/console v1.0.4/go.mod h1:YynlIjWYF8myEu6sdkwKIvGQq+cOckRm6So2avqoYAk= github.com/containerd/containerd/api v1.8.0 h1:hVTNJKR8fMc/2Tiw60ZRijntNMd1U+JVMyTRdsD2bS0= github.com/containerd/containerd/api v1.8.0/go.mod h1:dFv4lt6S20wTu/hMcP4350RL87qPWLVa/OHOwmmdnYc= -github.com/containerd/containerd/v2 v2.0.2 h1:GmH/tRBlTvrXOLwSpWE2vNAm8+MqI6nmxKpKBNKY8Wc= -github.com/containerd/containerd/v2 v2.0.2/go.mod h1:wIqEvQ/6cyPFUGJ5yMFanspPabMLor+bF865OHvNTTI= +github.com/containerd/containerd/v2 v2.0.3 h1:zBKgwgZsuu+LPCMzCLgA4sC4MiZzZ59ZT31XkmiISQM= +github.com/containerd/containerd/v2 v2.0.3/go.mod h1:5j9QUUaV/cy9ZeAx4S+8n9ffpf+iYnEj4jiExgcbuLY= github.com/containerd/continuity v0.4.5 h1:ZRoN1sXq9u7V6QoHMcVWGhOwDFqZ4B9i5H6un1Wh0x4= github.com/containerd/continuity v0.4.5/go.mod h1:/lNJvtJKUQStBzpVQ1+rasXO1LAWtUQssk28EZvJ3nE= github.com/containerd/errdefs v1.0.0 h1:tg5yIfIlQIrxYtu9ajqY42W3lpS19XqdxRQeEwYG8PI= @@ -401,8 +401,8 @@ github.com/tonistiigi/dchapes-mode v0.0.0-20241001053921-ca0759fec205 h1:eUk79E1 github.com/tonistiigi/dchapes-mode v0.0.0-20241001053921-ca0759fec205/go.mod h1:3Iuxbr0P7D3zUzBMAZB+ois3h/et0shEz0qApgHYGpY= github.com/tonistiigi/fsutil v0.0.0-20250113203817-b14e27f4135a h1:EfGw4G0x/8qXWgtcZ6KVaPS+wpWOQMaypczzP8ojkMY= github.com/tonistiigi/fsutil v0.0.0-20250113203817-b14e27f4135a/go.mod h1:Dl/9oEjK7IqnjAm21Okx/XIxUCFJzvh+XdVHUlBwXTw= -github.com/tonistiigi/go-actions-cache v0.0.0-20250219102945-1a5174abd055 h1:ocuqZe/ImPTYgDocnHTDOTBachfQ9m0JxvP4uGeDtBE= -github.com/tonistiigi/go-actions-cache v0.0.0-20250219102945-1a5174abd055/go.mod h1:h0oRlVs3NoFIHysRQ4rU1+RG4QmU0M2JVSwTYrB4igk= +github.com/tonistiigi/go-actions-cache v0.0.0-20250228231703-3e9a6642607f h1:q/SWz3Bz0KtAsqaBo73CHVXjaz5O8PDnmD2JHVhgYnE= +github.com/tonistiigi/go-actions-cache v0.0.0-20250228231703-3e9a6642607f/go.mod h1:h0oRlVs3NoFIHysRQ4rU1+RG4QmU0M2JVSwTYrB4igk= github.com/tonistiigi/go-archvariant v1.0.0 h1:5LC1eDWiBNflnTF1prCiX09yfNHIxDC/aukdhCdTyb0= github.com/tonistiigi/go-archvariant v1.0.0/go.mod h1:TxFmO5VS6vMq2kvs3ht04iPXtu2rUT/erOnGFYfk5Ho= github.com/tonistiigi/go-csvvalue v0.0.0-20240710180619-ddb21b71c0b4 h1:7I5c2Ig/5FgqkYOh/N87NzoyI9U15qUPXhDD8uCupv8= @@ -594,7 +594,7 @@ kernel.org/pub/linux/libs/security/libcap/psx v1.2.73/go.mod h1:+l6Ee2F59XiJ2I6W sigs.k8s.io/yaml v1.3.0/go.mod h1:GeOyir5tyXNByN85N/dRIT9es5UQNerPYEKK56eTBm8= sigs.k8s.io/yaml v1.4.0 h1:Mk1wCc2gy/F0THH0TAp1QYyJNzRm2KCLy3o5ASXVI5E= sigs.k8s.io/yaml v1.4.0/go.mod h1:Ejl7/uTz7PSA4eKMyQCUTnhZYNmLIl+5c2lQPGR2BPY= -tags.cncf.io/container-device-interface v0.8.0 h1:8bCFo/g9WODjWx3m6EYl3GfUG31eKJbaggyBDxEldRc= -tags.cncf.io/container-device-interface v0.8.0/go.mod h1:Apb7N4VdILW0EVdEMRYXIDVRZfNJZ+kmEUss2kRRQ6Y= +tags.cncf.io/container-device-interface v0.8.1 h1:c0jN4Mt6781jD67NdPajmZlD1qrqQyov/Xfoab37lj0= +tags.cncf.io/container-device-interface v0.8.1/go.mod h1:Apb7N4VdILW0EVdEMRYXIDVRZfNJZ+kmEUss2kRRQ6Y= tags.cncf.io/container-device-interface/specs-go v0.8.0 h1:QYGFzGxvYK/ZLMrjhvY0RjpUavIn4KcmRmVP/JjdBTA= tags.cncf.io/container-device-interface/specs-go v0.8.0/go.mod h1:BhJIkjjPh4qpys+qm4DAYtUyryaTDg9zris+AczXyws= diff --git a/vendor/github.com/containerd/containerd/v2/core/content/proxy/content_writer.go b/vendor/github.com/containerd/containerd/v2/core/content/proxy/content_writer.go index 214a0a335172..98818f234ab0 100644 --- a/vendor/github.com/containerd/containerd/v2/core/content/proxy/content_writer.go +++ b/vendor/github.com/containerd/containerd/v2/core/content/proxy/content_writer.go @@ -26,6 +26,7 @@ import ( digest "github.com/opencontainers/go-digest" "github.com/containerd/containerd/v2/core/content" + "github.com/containerd/containerd/v2/defaults" "github.com/containerd/containerd/v2/pkg/protobuf" ) @@ -76,27 +77,37 @@ func (rw *remoteWriter) Digest() digest.Digest { } func (rw *remoteWriter) Write(p []byte) (n int, err error) { - offset := rw.offset + const maxBufferSize = defaults.DefaultMaxSendMsgSize >> 1 + for i := 0; i < len(p); i += maxBufferSize { + offset := rw.offset - resp, err := rw.send(&contentapi.WriteContentRequest{ - Action: contentapi.WriteAction_WRITE, - Offset: offset, - Data: p, - }) - if err != nil { - return 0, fmt.Errorf("failed to send write: %w", errgrpc.ToNative(err)) - } + end := i + maxBufferSize + if end > len(p) { + end = len(p) + } + data := p[i:end] + + resp, err := rw.send(&contentapi.WriteContentRequest{ + Action: contentapi.WriteAction_WRITE, + Offset: offset, + Data: data, + }) + if err != nil { + return 0, fmt.Errorf("failed to send write: %w", errgrpc.ToNative(err)) + } - n = int(resp.Offset - offset) - if n < len(p) { - err = io.ErrShortWrite - } + written := int(resp.Offset - offset) + rw.offset += int64(written) + if resp.Digest != "" { + rw.digest = digest.Digest(resp.Digest) + } + n += written - rw.offset += int64(n) - if resp.Digest != "" { - rw.digest = digest.Digest(resp.Digest) + if written < len(data) { + return n, io.ErrShortWrite + } } - return + return n, nil } func (rw *remoteWriter) Commit(ctx context.Context, size int64, expected digest.Digest, opts ...content.Opt) (err error) { diff --git a/vendor/github.com/containerd/containerd/v2/pkg/oci/spec_opts.go b/vendor/github.com/containerd/containerd/v2/pkg/oci/spec_opts.go index 5101c63bb638..3b85d764ae10 100644 --- a/vendor/github.com/containerd/containerd/v2/pkg/oci/spec_opts.go +++ b/vendor/github.com/containerd/containerd/v2/pkg/oci/spec_opts.go @@ -28,18 +28,17 @@ import ( "strconv" "strings" - "github.com/containerd/containerd/v2/core/containers" - "github.com/containerd/containerd/v2/core/content" - "github.com/containerd/containerd/v2/core/images" - "github.com/containerd/containerd/v2/core/mount" - "github.com/containerd/containerd/v2/pkg/namespaces" "github.com/containerd/continuity/fs" - "github.com/containerd/log" "github.com/containerd/platforms" "github.com/moby/sys/user" v1 "github.com/opencontainers/image-spec/specs-go/v1" "github.com/opencontainers/runtime-spec/specs-go" - "tags.cncf.io/container-device-interface/pkg/cdi" + + "github.com/containerd/containerd/v2/core/containers" + "github.com/containerd/containerd/v2/core/content" + "github.com/containerd/containerd/v2/core/images" + "github.com/containerd/containerd/v2/core/mount" + "github.com/containerd/containerd/v2/pkg/namespaces" ) // SpecOpts sets spec specific information to a newly generated OCI spec @@ -1643,31 +1642,3 @@ func WithWindowsNetworkNamespace(ns string) SpecOpts { return nil } } - -// WithCDIDevices injects the requested CDI devices into the OCI specification. -func WithCDIDevices(devices ...string) SpecOpts { - return func(ctx context.Context, _ Client, c *containers.Container, s *Spec) error { - if len(devices) == 0 { - return nil - } - - if err := cdi.Refresh(); err != nil { - // We don't consider registry refresh failure a fatal error. - // For instance, a dynamically generated invalid CDI Spec file for - // any particular vendor shouldn't prevent injection of devices of - // different vendors. CDI itself knows better and it will fail the - // injection if necessary. - log.G(ctx).Warnf("CDI registry refresh failed: %v", err) - } - - if _, err := cdi.InjectDevices(s, devices...); err != nil { - return fmt.Errorf("CDI device injection failed: %w", err) - } - - // One crucial thing to keep in mind is that CDI device injection - // might add OCI Spec environment variables, hooks, and mounts as - // well. Therefore it is important that none of the corresponding - // OCI Spec fields are reset up in the call stack once we return. - return nil - } -} diff --git a/vendor/github.com/containerd/containerd/v2/version/version.go b/vendor/github.com/containerd/containerd/v2/version/version.go index 28f46ed09cab..d0749a6cfcd3 100644 --- a/vendor/github.com/containerd/containerd/v2/version/version.go +++ b/vendor/github.com/containerd/containerd/v2/version/version.go @@ -23,7 +23,7 @@ var ( Package = "github.com/containerd/containerd/v2" // Version holds the complete version number. Filled in at linking time. - Version = "2.0.2+unknown" + Version = "2.0.3+unknown" // Revision is filled with the VCS (e.g. git) revision being used to build // the program at linking time. diff --git a/vendor/github.com/tonistiigi/go-actions-cache/cache_v2.go b/vendor/github.com/tonistiigi/go-actions-cache/cache_v2.go index adbcda30eb68..6bf7ec3c084e 100644 --- a/vendor/github.com/tonistiigi/go-actions-cache/cache_v2.go +++ b/vendor/github.com/tonistiigi/go-actions-cache/cache_v2.go @@ -5,7 +5,10 @@ import ( "context" "encoding/json" "io" + "time" + "github.com/Azure/azure-sdk-for-go/sdk/azcore" + "github.com/Azure/azure-sdk-for-go/sdk/azcore/policy" "github.com/Azure/azure-sdk-for-go/sdk/storage/azblob/blob" "github.com/Azure/azure-sdk-for-go/sdk/storage/azblob/blockblob" "github.com/pkg/errors" @@ -45,8 +48,18 @@ func (c *Cache) reserveV2(ctx context.Context, key string) (string, error) { return cr.SignedUploadURL, nil } +var azureOptions = &blockblob.ClientOptions{ + ClientOptions: azcore.ClientOptions{ + Retry: policy.RetryOptions{ + MaxRetries: 10, + MaxRetryDelay: 2 * time.Minute, + RetryDelay: 10 * time.Second, + }, + }, +} + func (c *Cache) uploadV2(ctx context.Context, url string, b Blob) error { - client, err := blockblob.NewClientWithNoCredential(url, nil) + client, err := blockblob.NewClientWithNoCredential(url, azureOptions) if err != nil { return errors.WithStack(err) } @@ -62,7 +75,7 @@ func (c *Cache) uploadV2(ctx context.Context, url string, b Blob) error { func (ce *Entry) downloadV2(ctx context.Context) ReaderAtCloser { return toReaderAtCloser(func(offset int64) (io.ReadCloser, error) { - client, err := blockblob.NewClientWithNoCredential(ce.URL, nil) + client, err := blockblob.NewClientWithNoCredential(ce.URL, azureOptions) if err != nil { return nil, errors.WithStack(err) } diff --git a/vendor/modules.txt b/vendor/modules.txt index 5f5ee4e5da65..7dfe5e911ffd 100644 --- a/vendor/modules.txt +++ b/vendor/modules.txt @@ -301,7 +301,7 @@ github.com/containerd/containerd/api/types/runc/options github.com/containerd/containerd/api/types/runtimeoptions/v1 github.com/containerd/containerd/api/types/task github.com/containerd/containerd/api/types/transfer -# github.com/containerd/containerd/v2 v2.0.2 +# github.com/containerd/containerd/v2 v2.0.3 ## explicit; go 1.22.0 github.com/containerd/containerd/v2/client github.com/containerd/containerd/v2/core/containers @@ -809,7 +809,7 @@ github.com/tonistiigi/dchapes-mode github.com/tonistiigi/fsutil github.com/tonistiigi/fsutil/copy github.com/tonistiigi/fsutil/types -# github.com/tonistiigi/go-actions-cache v0.0.0-20250219102945-1a5174abd055 +# github.com/tonistiigi/go-actions-cache v0.0.0-20250228231703-3e9a6642607f ## explicit; go 1.22 github.com/tonistiigi/go-actions-cache # github.com/tonistiigi/go-archvariant v1.0.0 @@ -1148,7 +1148,7 @@ kernel.org/pub/linux/libs/security/libcap/psx ## explicit; go 1.12 sigs.k8s.io/yaml sigs.k8s.io/yaml/goyaml.v2 -# tags.cncf.io/container-device-interface v0.8.0 +# tags.cncf.io/container-device-interface v0.8.1 ## explicit; go 1.20 tags.cncf.io/container-device-interface/internal/validation tags.cncf.io/container-device-interface/internal/validation/k8s diff --git a/vendor/tags.cncf.io/container-device-interface/pkg/cdi/cache.go b/vendor/tags.cncf.io/container-device-interface/pkg/cdi/cache.go index c2f7fe346376..9afa4b18202e 100644 --- a/vendor/tags.cncf.io/container-device-interface/pkg/cdi/cache.go +++ b/vendor/tags.cncf.io/container-device-interface/pkg/cdi/cache.go @@ -564,6 +564,14 @@ func (w *watch) update(dirErrors map[string]error, removed ...string) bool { update bool ) + // If we failed to create an fsnotify.Watcher we have a nil watcher here + // (but with autoRefresh left on). One known case when this can happen is + // if we have too many open files. In that case we always return true and + // force a refresh. + if w.watcher == nil { + return true + } + for dir, ok = range w.tracked { if ok { continue