66 "encoding/json"
77 "fmt"
88 "net/http"
9+ "os"
910 "os/exec"
1011 "path/filepath"
1112 "regexp"
@@ -109,9 +110,14 @@ func dockerPermissionDenied(out []byte) bool {
109110 if strings .Contains (lower , "cannot connect to the docker daemon" ) || strings .Contains (lower , "is the docker daemon running" ) {
110111 return true
111112 }
113+ if strings .Contains (lower , "connection refused" ) {
114+ return true
115+ }
112116 return false
113117}
114118
119+ const dockerAccessHint = "若 Manager 在容器内,请为 runner-manager 配置 group_add 使用宿主机 docker 组 GID(.env 中 DOCKER_GID=$(getent group docker | cut -d: -f3)),或使用 user: \" 0:0\" 以 root 访问 socket"
120+
115121// ContainerRunning 判断容器是否在运行
116122func ContainerRunning (ctx context.Context , containerName string ) (bool , error ) {
117123 out , err := dockerCmd (ctx , "inspect" , "-f" , "{{.State.Running}}" , containerName )
@@ -120,15 +126,32 @@ func ContainerRunning(ctx context.Context, containerName string) (bool, error) {
120126 return false , nil
121127 }
122128 if dockerPermissionDenied (out ) {
123- return false , fmt .Errorf ("无法访问 Docker(权限不足或无法连接 daemon)。若 Manager 在容器内,请为 runner-manager 配置 group_add 使用宿主机 docker 组 GID,或使用 user: \" 0:0 \" 以 root 访问 socket: %w" , err )
129+ return false , fmt .Errorf ("无法访问 Docker(权限不足或无法连接 daemon)。%s: %w" , dockerAccessHint , err )
124130 }
125- return false , fmt .Errorf ("docker inspect: %w" , err )
131+ // 其它 exit 1 多为权限/连接问题(如 socket 不可访问),统一给出提示
132+ return false , fmt .Errorf ("docker inspect 失败(%w)。%s" , err , dockerAccessHint )
126133 }
127134 return strings .TrimSpace (string (out )) == "true" , nil
128135}
129136
137+ // managerMustUseHostDocker 提示:容器模式下 Manager 必须用宿主机 Docker 创建 Runner 容器,不能把 DOCKER_HOST 设为 DinD
138+ const errContainerModeNeedHostDocker = "容器模式下 Manager 必须使用宿主机 Docker(unix socket)创建/启停 Runner 容器,不能使用 DinD。请在 .env 中移除或注释 DOCKER_HOST=tcp://runner-dind:2375,使 Manager 使用默认 unix:///var/run/docker.sock;DinD 仅供 Runner 容器内 Job 的 docker build 等使用"
139+
140+ func managerDockerHostIsDind () bool {
141+ h := os .Getenv ("DOCKER_HOST" )
142+ return strings .HasPrefix (strings .TrimSpace (h ), "tcp://" )
143+ }
144+
145+ // ManagerDockerHostIsDind 供启动时检查:若为 true 且开启容器模式,Manager 无法创建 Runner 容器
146+ func ManagerDockerHostIsDind () bool {
147+ return managerDockerHostIsDind ()
148+ }
149+
130150// StartRunnerContainer 若容器不存在则创建并启动,若存在则 start;创建时挂载 installDir 到 /runner
131151func StartRunnerContainer (ctx context.Context , cfg * config.Config , runnerName , installDir string ) error {
152+ if cfg .Runners .ContainerMode && managerDockerHostIsDind () {
153+ return fmt .Errorf ("%s" , errContainerModeNeedHostDocker )
154+ }
132155 cn := ContainerName (runnerName )
133156 running , err := ContainerRunning (ctx , cn )
134157 if err != nil {
0 commit comments