运行 使用 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