Search code examples
python-3.xbashdockerubuntunerdctl

How can I solve this error, b'/bin/bash: line 1: nerdctl: command not found\n'?


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

Solution

  • 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.