运行 使用 docker-compose 的图像的多个实例失败
Running multiple instances of an image with docker-compose fails
你好,我正在尝试部署 4 个 docker 容器,其中包含相同的图像(这是一个 Java Play 应用程序)和一个 Nginx,它应该在这些实例之间进行负载平衡。
我的 docker-compose
文件如下所示:
version: '2'
services:
api1:
tty: true
image: abfalterjakob/play-api
ports:
- "9000"
api2:
tty: true
image: abfalterjakob/play-api
ports:
- "9001"
api3:
tty: true
image: abfalterjakob/play-api
ports:
- "9002"
api4:
tty: true
image: abfalterjakob/play-api
ports:
- "9003"
nginx:
image: abfalterjakob/custom_nginx
ports:
- "80:80"
运行 其中一个 api 实例工作正常,但每当我尝试 运行 第二个实例时它崩溃并出现此错误:
Starting docker_api2_1
Attaching to docker_api2_1
api2_1 | tandard_init_linux.go:175: exec user process caused "no such file or directory" [recovered]
api2_1 | panic: standard_init_linux.go:175: exec user process caused "no such file or directory"
api2_1 |
api2_1 | goroutine 1 [running, locked to thread]:
api2_1 | panic(0x7de000, 0xc82013efc0)
api2_1 | /usr/local/go/src/runtime/panic.go:481 +0x3e6
api2_1 | github.com/urfave/cli.HandleAction.func1(0xc82011f2e8)
api2_1 | /go/src/github.com/opencontainers/runc/Godeps/_workspace/src/github.com/urfave/cli/app.go:478 +0x38e
api2_1 | panic(0x7de000, 0xc82013efc0)
api2_1 | /usr/local/go/src/runtime/panic.go:443 +0x4e9
api2_1 | github.com/opencontainers/runc/libcontainer.(*LinuxFactory).StartInitialization.func1(0xc82011ebf8, 0xc82001e038, 0xc82011ed08)
api2_1 | /go/src/github.com/opencontainers/runc/Godeps/_workspace/src/github.com/opencontainers/runc/libcontainer/factory_linux.go:259 +0x136
api2_1 | github.com/opencontainers/runc/libcontainer.(*LinuxFactory).StartInitialization(0xc8200d0f50, 0x7fa4847fc918, 0xc82013efc0)
api2_1 | /go/src/github.com/opencontainers/runc/Godeps/_workspace/src/github.com/opencontainers/runc/libcontainer/factory_linux.go:277 +0x5b1
api2_1 | main.glob.func8(0xc8200da3c0, 0x0, 0x0)
api2_1 | /go/src/github.com/opencontainers/runc/main_unix.go:26 +0x68
api2_1 | reflect.Value.call(0x744b00, 0x8f0ed0, 0x13, 0x839c18, 0x4, 0xc82011f268, 0x1, 0x1, 0x0, 0x0, ...)
api2_1 | /usr/local/go/src/reflect/value.go:435 +0x120d
api2_1 | reflect.Value.Call(0x744b00, 0x8f0ed0, 0x13, 0xc82011f268, 0x1, 0x1, 0x0, 0x0, 0x0)
api2_1 | /usr/local/go/src/reflect/value.go:303 +0xb1
api2_1 | github.com/urfave/cli.HandleAction(0x744b00, 0x8f0ed0, 0xc8200da3c0, 0x0, 0x0)
api2_1 | /go/src/github.com/opencontainers/runc/Godeps/_workspace/src/github.com/urfave/cli/app.go:487 +0x2ee
api2_1 | github.com/urfave/cli.Command.Run(0x83cab8, 0x4, 0x0, 0x0, 0x0, 0x0, 0x0, 0x8d0420, 0x51, 0x0, ...)
api2_1 | /go/src/github.com/opencontainers/runc/Godeps/_workspace/src/github.com/urfave/cli/command.go:191 +0xfec
api2_1 | github.com/urfave/cli.(*App).Run(0xc820001680, 0xc820070060, 0x2, 0x2, 0x0, 0x0)
api2_1 | /go/src/github.com/opencontainers/runc/Godeps/_workspace/src/github.com/urfave/cli/app.go:240 +0xaa4
api2_1 | main.main()
api2_1 | /go/src/github.com/opencontainers/runc/main.go:137 +0xe24
docker_api2_1 exited with code 2
我猜这可能是端口问题?
这里是 play 应用程序的 Dockerfile
FROM java:8
ADD target /app/target
ADD start_script.sh /app
WORKDIR /app
RUN chmod +x ./start_script.sh
CMD ["./start_script.sh"]
EXPOSE 9000
有人知道这里的确切问题是什么吗?
您可能不需要指定 ports
如果您不需要 API 服务器上的端口在 Docker 之外响应 ,则无需指定 ports
完全没有。图像中的 EXPOSE
语句已经存在。您的 nginx 容器已经可以访问 Docker 网络中每个 API 容器的端口 9000。
您需要 link 容器在一起以便它们可以通信
不过,您确实需要告诉 nginx 容器 link 给其他容器。尝试这样的事情:
version: '2'
services:
api1:
tty: true
image: abfalterjakob/play-api
api2:
tty: true
image: abfalterjakob/play-api
api3:
tty: true
image: abfalterjakob/play-api
api4:
tty: true
image: abfalterjakob/play-api
nginx:
image: abfalterjakob/custom_nginx
ports:
- "80:80"
links:
- api1
- api2
- api3
- api4
现在,您的 nginx 容器可以使用 API 服务器的服务和端口与它们通信,例如
api1:9000
api2:9000
api3:9000
api4:9000
这还有一个额外的好处,即您的 API 服务器与外部网络隔离,从而提高了安全性。
同样,这假定 API 服务器不应公开访问,而应仅通过 nginx 代理进行路由。
如果将端口映射到外部,则必须将内部映射到外部
你告诉Docker使用9000、9001等端口,但是你的image只设置了EXPOSE 9000。要将它们映射到外部,你需要设置外部端口,然后将其映射到内部端口,如下所示:
version: '2'
services:
api1:
tty: true
image: abfalterjakob/play-api
ports:
- "9000:9000"
api2:
tty: true
image: abfalterjakob/play-api
ports:
- "9001:9000"
api3:
tty: true
image: abfalterjakob/play-api
ports:
- "9002:9000"
api4:
tty: true
image: abfalterjakob/play-api
ports:
- "9003:9000"
nginx:
image: abfalterjakob/custom_nginx
ports:
- "80:80"
links:
- api1
- api2
- api3
- api4
在您的原始示例中,您只使用了一个端口。这告诉 docker-compose 使用该容器端口,但安排一个随机主机端口。如果你告诉他们每个人使用端口 9000,它就会将每个容器中的端口 9000 绑定到一个随机的主机端口。但是您在 4 个案例中的 3 个中指定了非暴露的容器端口。
有关更多信息,请参阅 Compose file reference。
你好,我正在尝试部署 4 个 docker 容器,其中包含相同的图像(这是一个 Java Play 应用程序)和一个 Nginx,它应该在这些实例之间进行负载平衡。
我的 docker-compose
文件如下所示:
version: '2'
services:
api1:
tty: true
image: abfalterjakob/play-api
ports:
- "9000"
api2:
tty: true
image: abfalterjakob/play-api
ports:
- "9001"
api3:
tty: true
image: abfalterjakob/play-api
ports:
- "9002"
api4:
tty: true
image: abfalterjakob/play-api
ports:
- "9003"
nginx:
image: abfalterjakob/custom_nginx
ports:
- "80:80"
运行 其中一个 api 实例工作正常,但每当我尝试 运行 第二个实例时它崩溃并出现此错误:
Starting docker_api2_1
Attaching to docker_api2_1
api2_1 | tandard_init_linux.go:175: exec user process caused "no such file or directory" [recovered]
api2_1 | panic: standard_init_linux.go:175: exec user process caused "no such file or directory"
api2_1 |
api2_1 | goroutine 1 [running, locked to thread]:
api2_1 | panic(0x7de000, 0xc82013efc0)
api2_1 | /usr/local/go/src/runtime/panic.go:481 +0x3e6
api2_1 | github.com/urfave/cli.HandleAction.func1(0xc82011f2e8)
api2_1 | /go/src/github.com/opencontainers/runc/Godeps/_workspace/src/github.com/urfave/cli/app.go:478 +0x38e
api2_1 | panic(0x7de000, 0xc82013efc0)
api2_1 | /usr/local/go/src/runtime/panic.go:443 +0x4e9
api2_1 | github.com/opencontainers/runc/libcontainer.(*LinuxFactory).StartInitialization.func1(0xc82011ebf8, 0xc82001e038, 0xc82011ed08)
api2_1 | /go/src/github.com/opencontainers/runc/Godeps/_workspace/src/github.com/opencontainers/runc/libcontainer/factory_linux.go:259 +0x136
api2_1 | github.com/opencontainers/runc/libcontainer.(*LinuxFactory).StartInitialization(0xc8200d0f50, 0x7fa4847fc918, 0xc82013efc0)
api2_1 | /go/src/github.com/opencontainers/runc/Godeps/_workspace/src/github.com/opencontainers/runc/libcontainer/factory_linux.go:277 +0x5b1
api2_1 | main.glob.func8(0xc8200da3c0, 0x0, 0x0)
api2_1 | /go/src/github.com/opencontainers/runc/main_unix.go:26 +0x68
api2_1 | reflect.Value.call(0x744b00, 0x8f0ed0, 0x13, 0x839c18, 0x4, 0xc82011f268, 0x1, 0x1, 0x0, 0x0, ...)
api2_1 | /usr/local/go/src/reflect/value.go:435 +0x120d
api2_1 | reflect.Value.Call(0x744b00, 0x8f0ed0, 0x13, 0xc82011f268, 0x1, 0x1, 0x0, 0x0, 0x0)
api2_1 | /usr/local/go/src/reflect/value.go:303 +0xb1
api2_1 | github.com/urfave/cli.HandleAction(0x744b00, 0x8f0ed0, 0xc8200da3c0, 0x0, 0x0)
api2_1 | /go/src/github.com/opencontainers/runc/Godeps/_workspace/src/github.com/urfave/cli/app.go:487 +0x2ee
api2_1 | github.com/urfave/cli.Command.Run(0x83cab8, 0x4, 0x0, 0x0, 0x0, 0x0, 0x0, 0x8d0420, 0x51, 0x0, ...)
api2_1 | /go/src/github.com/opencontainers/runc/Godeps/_workspace/src/github.com/urfave/cli/command.go:191 +0xfec
api2_1 | github.com/urfave/cli.(*App).Run(0xc820001680, 0xc820070060, 0x2, 0x2, 0x0, 0x0)
api2_1 | /go/src/github.com/opencontainers/runc/Godeps/_workspace/src/github.com/urfave/cli/app.go:240 +0xaa4
api2_1 | main.main()
api2_1 | /go/src/github.com/opencontainers/runc/main.go:137 +0xe24
docker_api2_1 exited with code 2
我猜这可能是端口问题? 这里是 play 应用程序的 Dockerfile
FROM java:8
ADD target /app/target
ADD start_script.sh /app
WORKDIR /app
RUN chmod +x ./start_script.sh
CMD ["./start_script.sh"]
EXPOSE 9000
有人知道这里的确切问题是什么吗?
您可能不需要指定 ports
如果您不需要 API 服务器上的端口在 Docker 之外响应 ,则无需指定 ports
完全没有。图像中的 EXPOSE
语句已经存在。您的 nginx 容器已经可以访问 Docker 网络中每个 API 容器的端口 9000。
您需要 link 容器在一起以便它们可以通信
不过,您确实需要告诉 nginx 容器 link 给其他容器。尝试这样的事情:
version: '2'
services:
api1:
tty: true
image: abfalterjakob/play-api
api2:
tty: true
image: abfalterjakob/play-api
api3:
tty: true
image: abfalterjakob/play-api
api4:
tty: true
image: abfalterjakob/play-api
nginx:
image: abfalterjakob/custom_nginx
ports:
- "80:80"
links:
- api1
- api2
- api3
- api4
现在,您的 nginx 容器可以使用 API 服务器的服务和端口与它们通信,例如
api1:9000
api2:9000
api3:9000
api4:9000
这还有一个额外的好处,即您的 API 服务器与外部网络隔离,从而提高了安全性。
同样,这假定 API 服务器不应公开访问,而应仅通过 nginx 代理进行路由。
如果将端口映射到外部,则必须将内部映射到外部
你告诉Docker使用9000、9001等端口,但是你的image只设置了EXPOSE 9000。要将它们映射到外部,你需要设置外部端口,然后将其映射到内部端口,如下所示:
version: '2'
services:
api1:
tty: true
image: abfalterjakob/play-api
ports:
- "9000:9000"
api2:
tty: true
image: abfalterjakob/play-api
ports:
- "9001:9000"
api3:
tty: true
image: abfalterjakob/play-api
ports:
- "9002:9000"
api4:
tty: true
image: abfalterjakob/play-api
ports:
- "9003:9000"
nginx:
image: abfalterjakob/custom_nginx
ports:
- "80:80"
links:
- api1
- api2
- api3
- api4
在您的原始示例中,您只使用了一个端口。这告诉 docker-compose 使用该容器端口,但安排一个随机主机端口。如果你告诉他们每个人使用端口 9000,它就会将每个容器中的端口 9000 绑定到一个随机的主机端口。但是您在 4 个案例中的 3 个中指定了非暴露的容器端口。
有关更多信息,请参阅 Compose file reference。