golang在docker容器中执行linux命令

443 阅读2分钟

背景

最近用golang来执行linux的命令,想得很简单,实施起来没想到踩了这么多坑,运行环境是在docker容器里

实际代码逻辑操作步骤

flowchart TD
    A[执行./test] --> B{输出判断}
    B --> |no display...| C[执行Xvfb :54321 -ac &]
    B -->|成功的输出| D[对输出结果判断]
    C --> E[执行 ./test,判断输出结果]

注:1.Xvfb :54321 -ac &命令作用是启动虚拟桌面环境,保持后台运行,test可执行文件的执行需要依赖于这个进程

坑点

1.使用go的官方包"os/exec"操作,代码如下:

output,err := exec.Command("Xvfb",":35535 -ac", "&").CombinedOutput()

这个代码会输出未识别的标识&,这里各种排列组合传参还是会报错误,后面查询得到解决方案,如下:

output,err := exec.Command("bash", "-c", "Xvfb :35535 -ac &").CombinedOutput()

用bash -c后跟命令来执行就不会有问题,-c选项表示执行命令,bash命令详解:www.linuxcool.com/bash
2.1中坑解决后,但是同样遇到了问题,goroutine运行到这段执行命令的代码后阻塞了,导致后续的代码无法执行,这里网上查了很多资料也没有解决,后面自己琢磨看"os/exec"包的源码,把CombinedOutput()换成Run函数解决,代码如下:

output,err := exec.Command("bash", "-c", "Xvfb :35535 -ac &").Run()

看哈包中把CombinedOutput()函数的注释:

// CombinedOutput runs the command and returns its combined standard
// output and standard error.

翻译:CombinedOutput运行命令并返回其组合标准
Run()函数的注释:

// Run starts the specified command and waits for it to complete.
//
// The returned error is nil if the command runs, has no problems
// copying stdin, stdout, and stderr, and exits with a zero exit
// status.
//
// If the command starts but does not complete successfully, the error is of
// type *ExitError. Other error types may be returned for other situations.
//
// If the calling goroutine has locked the operating system thread
// with runtime.LockOSThread and modified any inheritable OS-level
// thread state (for example, Linux or Plan 9 name spaces), the new
// process will inherit the caller's thread state.

翻译:运行启动指定的命令并等待其完成
3.容器启动时
第一个goroutine开始,会走代码逻辑中的左边个分支,依次执行Xvfb :54321 -ac &,然后执行test执行文件,但是执行test执行文件时,依然会输出no dislolay....的错误,感觉好像是没执行到Xvfb
第二个goroutine进来,会走代码逻辑右边的分支,执行test文件成功并拿到输出结果,后续的gotoutine都能成功执行test文件
这的具体原因还未研究出来,后续是放弃了这种思路,把Xvfb的执行直接放到docker-compose.yml文件中