0

I have written a python script to run the commands to execute nerdctl shell commands using subprocess,

 res = subprocess.run(
      f"nerdctl --host '/host/run/containerd/containerd.sock' --namespace k8s.io commit {container} {image}",
      shell=True, stdout=subprocess.PIPE, stderr=subprocess.PIPE, executable='/bin/bash')

I'm running this python script inside a ubuntu container, When I sh inside the conatiner and run this script by passing arguments

python3 run_script.py b3425e7a0d1e image1

it executes properly, but when I run it using debug mode

kubectl debug node/pool-93oi9uqaq-mfs8b -it --image=registry.digitalocean.com/test-registry-1/nerdctl@sha256:56b2e5690e21a67046787e13bb690b3898a4007978187800dfedd5c56d45c7b2  -- python3 run_script.py b3425e7a0d1e image1

I'm getting the error

b'/bin/bash: line 1: nerdctl: command not found\n'

can some one help/suggest where it is going wrong?

run_script.py

import subprocess
import sys

container = sys.argv[1]
image = sys.argv[2]

res = subprocess.run(
      f"nerdctl --host '/host/run/containerd/containerd.sock' --namespace k8s.io commit {container} {image}",
      shell=True, stdout=subprocess.PIPE, stderr=subprocess.PIPE, executable='/bin/bash')

print(res)

Dockerfile

FROM ubuntu:latest
RUN rm /bin/sh && ln -s /bin/bash /bin/sh
LABEL version="0.1.0"

RUN apt-get -y update
RUN apt-get install wget curl  -y
RUN wget -q "https://github.com/containerd/nerdctl/releases/download/v1.0.0/nerdctl-full-1.0.0-linux-amd64.tar.gz" -O /tmp/nerdctl.tar.gz
RUN mkdir -p ~/.local/bin
RUN tar -C ~/.local/bin/ -xzf /tmp/nerdctl.tar.gz --strip-components 1 bin/nerdctl
RUN echo -e '\nexport PATH="${PATH}:~/.local/bin"' >> ~/.bashrc
RUN source ~/.bashrc
  • 1
    Is `nerdctl` in one of the `$PATH` directories? If not, then you need to provide an explicit path to it, absolute or relative. `./nerdctl` would be a relative path example if it is located in the current `$PWD`. – Andrej Podzimek Dec 27 '22 at 04:36
  • I have added the dockerfile info, i'm saving it location as shown there. – Anil Kumar H P Dec 27 '22 at 05:03
  • ```root@pool-93oi9uqaq-mfs8b:/# nerdctl version WARN[0000] unable to determine buildctl version: exec: "buildctl": executable file not found in $PATH Client: Version: v1.0.0 OS/Arch: linux/amd64 Git commit: c00780a1f5b905b09812722459c54936c9e070e6 buildctl: Version: FATA[0000] cannot access containerd socket "/run/containerd/containerd.sock": no such file or directory``` – Anil Kumar H P Dec 27 '22 at 05:06
  • When I run nerdctl version it is giving the version details. – Anil Kumar H P Dec 27 '22 at 05:12
  • @AndrejPodzimek : Note that the error message starts with `b'/bin/bash` and ends with a literal `\n`. While I think too that `nerdctl` is not in the PATH, I feel that this is not the only problem here. – user1934428 Dec 27 '22 at 07:40
  • @AnilKumarHP : The docker info suggests that `nerdctl` indeed **is** in the PATH, but `buildctl` seems to be missing (_unable to determine buildctl version ... executable file not found_). – user1934428 Dec 27 '22 at 07:49
  • I solved the issue by copying nerdctl to /usr/local/bin/. Thank you all for suggestion and help. – Anil Kumar H P Dec 27 '22 at 09:24

1 Answers1

1

Mechanically: the binary you're installing isn't in $PATH anywhere. You unpack it into probably /root/.local/bin in the container filesystem but never add that to $PATH. The final RUN source line has no effect since each RUN command runs in a new shell (and technically a new container) and so the changes it makes are lost immediately. The preceding line tries to change a shell dotfile, but most paths to running things in Docker don't read shell dotfiles at all.

The easiest solution here is to unpack the binary into a directory that's already in $PATH, like /usr/local/bin.

FROM ubuntu:latest
LABEL version="0.1.0"

RUN apt-get update \
 && DEBIAN_FRONTEND=noninteractive \
    apt-get install --no-install-recommends --assume-yes \
      wget

RUN wget -q "https://github.com/containerd/nerdctl/releases/download/v1.0.0/nerdctl-full-1.0.0-linux-amd64.tar.gz" -O /tmp/nerdctl.tar.gz \
 && tar -C /usr/local -xzf /tmp/nerdctl.tar.gz bin/nerdctl \
 && rm /tmp/nerdctl.tar.gz

WORKDIR /app
...
CMD ["./run_script.py"]

You'll have a second bigger problem running this, though. A container doesn't normally have access to the host's container runtime to be able to manipulate containers. In standard Docker you can trivially root the host system if you can launch a container; it's possible to mount the Docker socket into a container but does require thinking hard about the security implications.

Your question has several hints at Kubernetes and I'd expect a responsible cluster administrator to make it hard-to-impossible to bypass the cluster container runtime and potentially compromise nodes this way. If you're using Kubernetes you probably can't access the host container runtime at all, whether it's Docker proper or something else.

Philosophically, it looks like you're trying to script a commit command. Using commit at all is almost never a best practice. Again, there are several practical problems with it around Kubernetes (which replica would you be committing? how would you save the resulting image? how would you reuse it?) but having an image you can't recreate from source can lead to later problems around for example taking security updates.

David Maze
  • 130,717
  • 29
  • 175
  • 215