Docker|--镜像中既有gcc和.NET运行时, 但是容器启动的时候报错 exec: "dotnet": executable file not found in $PATH: unknown.

发布时间 2023-12-01 17:32:56作者: zh89233

基本信息


# 镜像gcc_for_net7_image是如何产生的, 分为3步
1.基于gcc的镜像运行起来的一个包含了gcc环境的容器, 
2.在这个容器里安装了.NET7运行时, 
3.再将这个包含了gcc环境和.NET7的容器打包为一个镜像"gcc_for_net7_image"

总之, 这个镜像"gcc_for_net7_image"既包含了gcc开发环境, 也包含了.NET7开发环境

# 基于这个基础镜像"gcc_for_net7_image", 想生成一个api应用程序的镜像, 但是运行此api应用程序的容器时候, 报错...

# 多说一句, 为什么我要搞这个一个镜像, 既包含gcc开发环境, 又包含.NET开发环境
我的api应用程序是基于.NET写的, 但是我的这个api程序, 又要调用c++的一些东西,特别是涉及一些画图之类的, 所以, 最终搞了这么一个镜像~~~

报错信息


docker: Error response from daemon: failed to create shim: OCI runtime create failed: container_linux.go:380: starting container process caused: exec: "dotnet": executable file not found in $PATH: unknown.

原因查找


# 启动容器
docker run -id --name gcc_for_net7_container gcc_for_net7_image

# 使用"/bin/bash"进入容器, 发现执行gcc或者dotnet, 命令都有可以的~
docker exec -it gcc_for_net7_container /bin/bash

# 使用"/bin/sh"进入容器会发现执行gcc不报错,但是执行dotnet报错!
docker exec -it gcc_for_net7_container /bin/sh

# gcc
gcc: fatal error: no input files
compilation terminated.
# dotnet
/bin/sh: 4: dotnet: not found

通过这个容器, 会发现,
使用"/bin/bash"的情况下, gcc和dotnet命令都可以执行,
但是使用"/bin/sh"的情况下, gcc可以执行, 但是dotnet命令没有~
所以我就想着改一下,Dockerfile中的内容~


# 进一步发现, 只有"/bin/bash"下可以执行dotnet, 如果在启动docker容器的时候, 使用交互方式方式"-t", 直接使用"dotnet"也报错!

$ docker run -id --name gcc_for_net7_container  gcc_for_net7_image:v1
1xxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxx1

$ docker exec -it gcc_for_net7_container dotnet

OCI runtime exec failed: exec failed: container_linux.go:380: 
starting container process caused: exec: "dotnet": executable file not found in $PATH: unknown

初步确定原因如下 :

  1. 当使用bash进入容器的时候, 环境变量PATH的路径会增加dotnet需要的路径$HOME/dotnet
  2. 当使用sh进入容器的时候, 环境变量PATH的路径中没有dotnet需要的路径
  3. 直接交互, docker run -it gcc_for_net7_container dotnet 这样操作, PATH路径更是没有配置dotnet需要的路径~
    总之, 想办法把PATH路径配置好~

解决方案( docker run的时候增加-e配置 )


# docker容器启动的时候增加参数 -e PATH="$PATH:$HOME/dotnet"
$ docker run -id --name gcc_for_net7_container -e PATH="$PATH:$HOME/dotnet" gcc_for_net7_image:v1

# 验证是否可行( 可以看到,交互方式进入容器是可以直接发现dotnet命令的! )

$ docker exec -it gcc_for_net7_container dotnet

Usage: dotnet [options]
Usage: dotnet [path-to-application]

Options:
  -h|--help         Display help.
  --info            Display .NET information.
  --list-sdks       Display the installed SDKs.
  --list-runtimes   Display the installed runtimes.

path-to-application:
  The path to an application .dll file to execute.

关于启动镜像介绍


# 1. 镜像gcc_for_net7_image中既有gcc开发环境, 又有.NET7运行时
# 2. 这个镜像是基于一个"既有gcc开发环境, 又有.NET7运行时"的容器生成的, 并且该容器已经配置好了dotnet的PATH路径
# 2.1. dotnet的PATH路径配置方法是 : # 
# 2.1.1. 修改PATH变量 "vim /etc/profile", 在PATH赋值的地方增加上":/root/dotnet"
# 2.1.1. 在容器实例"/root/.bashrc"配置文件末尾添加(首先vim /root/.bashrc)"source /etc/profile",保存退出即可, 这样能够实现重启后自动刷新配置文件.

反思,,,


还是对进入容器"docker exec"的不同方式, 区别理解不深, 
"bash" / "sh" / "dotnet" ...都会发生什么?

# 问了下chatGPT, 发现问题所在( 如果chatGPT没有骗我的话 ~ )
# 问 : 
Linux容器的"/root/.bashrc"是何时触发的?

# 答 : 
在Linux容器中,/root/.bashrc 文件通常在每次以交互方式启动新的bash shell时触发。
这个文件包含了在每次打开新的bash shell时要执行的命令和设置。
具体来说,当以下情况之一发生时,/root/.bashrc 文件将被触发:

1. 登录交互式Shell: 当你登录到系统时,或者通过SSH等方式远程登录到容器,
并且使用bash shell时,/root/.bashrc 将被执行。
2. 新的终端会话: 每次你启动一个新的终端会话(比如打开一个新的终端窗口或标签页),
并且该终端使用bash shell时,/root/.bashrc 也会被执行。
3. 执行bash命令: 当你在已有的bash shell中执行 bash 命令来启动一个新的bash子shell时,/root/.bashrc 也会被执行。

这个文件通常用于设置用户的个性化环境变量、别名、函数以及其他一些个性化的配置。

最终明白了, 由于我的PATH是配置在了/etc/profile中,
我的{sourcee /etc/profile}又是在"/root/.bashrc"中配置的,
所以就导致了, 我只有在bash命令的时候{docker exec -it gcc_for_net7_container /bin/bash}才会配置了PATH路径,才有dotnet命令,
反之, 我使用sh{docker exec -it gcc_for_net7_container /bin/sh}和{docker exec -it gcc_for_net7_container dotnet}的时候,
根本不会去触发"/root/.bashrc", 也就不会执行{sourcee /etc/profile}, 所以PATH没有增加dotnet需要的路径~