从另一个容器访问 docker 容器

Posted

技术标签:

【中文标题】从另一个容器访问 docker 容器【英文标题】:accessing a docker container from another container 【发布时间】:2017-07-12 04:14:51 【问题描述】:

我基于两个不同的图像创建了两个 docker 容器。一个 db 和另一个用于网络服务器。两个容器都在我的 mac osx 上运行。

我可以从主机访问数据库容器,同样的方式可以从主机访问网络服务器。

但是,如何从网络服务器访问数据库连接?

我启动db容器的方式是

docker run --name oracle-db -p 1521:1521 -p 5501:5500 oracle/database:12.1.0.2-ee

我启动 wls 容器为

docker run --name oracle-wls -p 7001:7001 wls-image:latest

我可以通过连接来访问主机上的数据库

sqlplus scott/welcome1@//localhost:1521/ORCLCDB

我可以访问主机上的 wls

http://localhost:7001/console

【问题讨论】:

那么web容器和db容器都在宿主机上?如果是这样,您使用的是哪个版本的 docker?因为旧版本的 docker 有一种方法,而新版本有不同的方法。你也可以使用 docker-compose 吗?这会更容易,但我不想用你不能用的方法给出答案。 this answer 可能会有所帮助,如何从 mac os 中的容器访问 localhost 对于外部网络,这个解决方案对我有用***.com/a/38089080/1770571 这能回答你的问题吗? How to get Docker containers to talk to each other while running on my local host? 【参考方案1】:

这很容易。 如果您有两个或更多正在运行的容器,请完成以下步骤:

docker network create myNetwork
docker network connect myNetwork web1
docker network connect myNetwork web2

现在您从 web1 连接到 web2 容器,或者反过来。

使用你可以通过运行找到的内部网络IP地址:

docker network inspect myNetwork

请注意,通过网桥连接的容器只能访问内部 IP 地址和端口。

因此例如假设 web1 容器以:docker run -p 80:8888 web1 启动(意味着它的服务器在内部运行在端口 8888 上),并且检查 myNetwork 显示 web1 的 IP 是 172.0.0.2,您可以从 web2 连接到web1 使用curl 172.0.0.2:8888)。

【讨论】:

嗨,我如何从 web1 连接到 web2?通过 ip,主机名?从哪里获得这些信息? 在文件 docker-compose.yml 中创建网络:myNetwork. @HenryÁvila 您只需使用容器的名称(例如web1)作为主机名。 不客气。【参考方案2】:

最简单的方法是使用 --link,但是新版本的 docker 正在远离它,事实上这个开关很快就会被移除。

下面的链接也提供了一个很好的方法,用于连接两个容器。您可以跳过附加部分,因为这只是向图像添加项目的有用方法。

https://web.archive.org/web/20160310072132/https://deis.com/blog/2016/connecting-docker-containers-1/

您感兴趣的部分是两个容器之间的通信。最简单的方法是从 webserver 容器中按名称引用 DB 容器。

例子:

您将 db 容器命名为 db1 和 webserver 容器 web0。容器应该都在桥接网络上,这意味着 Web 容器应该能够通过引用它的名称连接到 DB 容器。

因此,如果您的应用有 Web 配置文件,那么对于 DB 主机,您将使用名称 db1

如果您使用的是旧版本的 docker,那么您应该使用 --link。

例子:

第一步:docker run --name db1 oracle/database:12.1.0.2-ee

然后当您启动网络应用程序时。使用:

第二步:docker run --name web0 --link db1 webapp/webapp:3.0

并且网络应用程序将链接到数据库。但是,正如我所说,--link 开关很快就会被移除。

我会改用 docker compose,它会为你构建一个网络。然而;您需要为您的系统下载 docker compose。 https://docs.docker.com/compose/install/#prerequisites

一个示例设置如下:

文件名为base.yml

version: "2"
services:
  webserver:
    image: moodlehq/moodle-php-apache:7.1
    depends_on:
      - db
    volumes:
      - "/var/www/html:/var/www/html"
      - "/home/some_user/web/apache2_faildumps.conf:/etc/apache2/conf-enabled/apache2_faildumps.conf"
    environment:
      MOODLE_DOCKER_DBTYPE: pgsql
      MOODLE_DOCKER_DBNAME: moodle
      MOODLE_DOCKER_DBUSER: moodle
      MOODLE_DOCKER_DBPASS: "m@0dl3ing"
      HTTP_PROXY: "$HTTP_PROXY"
      HTTPS_PROXY: "$HTTPS_PROXY"
      NO_PROXY: "$NO_PROXY"
  db:
    image: postgres:9
    environment:
      POSTGRES_USER: moodle
      POSTGRES_PASSWORD: "m@0dl3ing"
      POSTGRES_DB: moodle
      HTTP_PROXY: "$HTTP_PROXY"
      HTTPS_PROXY: "$HTTPS_PROXY"
      NO_PROXY: "$NO_PROXY"

这会将网络命名为通用名称,除非您使用 --name 开关,否则我不记得该名称是什么了。

IEdocker-compose --name setup1 up base.yml

注意:如果您使用 --name 开关,则在调用 docker compose 时需要使用它,所以docker-compose --name setup1 down 这样您就可以拥有多个 webserver 和 db 实例,在这种情况下,所以 docker compose 知道您要针对哪个实例运行命令;而且你可以同时运行不止一个。非常适合 CI/CD,如果您在同一台服务器上并行运行测试。

Docker compose 也有和 docker 一样的命令,所以docker-compose --name setup1 exec webserver do_some_command

最好的部分是,如果你想更改 db 或类似的东西进行单元测试,你可以在 up 命令中包含一个额外的 .yml 文件,它会覆盖任何具有相似名称的项目,我认为它是一个 key= >价值替换。

例子:

db.yml

version: "2"
services:
  webserver:
    environment:
      MOODLE_DOCKER_DBTYPE: oci
      MOODLE_DOCKER_DBNAME: XE
  db:
    image: moodlehq/moodle-db-oracle

然后拨打docker-compose --name setup1 up base.yml db.yml

这将覆盖数据库。使用不同的设置。当需要从每个容器连接到这些服务时,您使用服务下设置的名称,在本例中为 webserver 和 db。

我认为在您的情况下,这实际上可能是一个更有用的设置。由于您可以在 yml 文件中设置所需的所有变量,并在需要启动它们时运行 docker compose 命令。所以更多的启动它并忘记它的设置。

注意:我没有使用--port 命令,因为容器->容器通信不需要公开端口。仅当您希望主机连接到容器或主机外部的应用程序时才需要它。如果您公开端口,则该端口对主机允许的所有通信都是开放的。因此,在端口 80 上公开 Web 与在物理主机上启动 Web 服务器相同,并且如果主机允许,将允许外部连接。此外,如果您想同时运行多个 Web 应用程序,无论出于何种原因,如果您也尝试在该端口上暴露,那么暴露端口 80 将阻止您运行其他 Web 应用程序。因此,对于 CI/CD,最好根本不公开端口,如果使用带有 --name 开关的 docker compose,所有容器都将位于它们自己的网络上,因此它们不会发生冲突。所以你几乎会有一个容器容器。

更新:在进一步使用功能并查看其他人如何为 Jenkins 等 CICD 程序完成它之后。网络也是一种可行的解决方案。

例子:

docker network create test_network

上述命令将创建一个“test_network”,您也可以附加其他容器。使用--network 开关运算符可以轻松实现。

例子:

docker run \
    --detach \
    --name db1 \
    --network test_network \
    -e mysql_ROOT_PASSWORD="$DBPASS" \
    -e MYSQL_DATABASE="$DBNAME" \
    -e MYSQL_USER="$DBUSER" \
    -e MYSQL_PASSWORD="$DBPASS" \
    --tmpfs /var/lib/mysql:rw \
    mysql:5

当然,如果您有代理网络设置,您仍然应该使用“-e”或“--env-file”开关语句将它们传递到容器中。所以容器可以与互联网通信。 Docker 说代理设置应该被新版本的 docker 中的容器吸收;但是,我仍然将它们作为一种习惯行为传递。这是即将消失的“--link”开关的替代品。将容器连接到您创建的网络后,您仍然可以使用容器的“名称”从其他容器中引用这些容器。根据上面的示例,这将是db1。您只需确保所有容器都连接到同一个网络,就可以开始了。

关于在 cicd 管道中使用网络的详细示例,您可以参考此链接: https://git.in.moodle.com/integration/nightlyscripts/blob/master/runner/master/run.sh

这是在 Jenkins 中运行的用于 Moodle 的大型集成测试的脚本,但该想法/示例可以在任何地方使用。我希望这对其他人有所帮助。

【讨论】:

如果第一个链接不起作用,您可以使用这个。 linode.com/docs/applications/containers/… 对于做 Docker 撰写或做网络,网络服务器将如何引用数据库?它会使用容器的名称吗?在第二个链接中看起来就是这种情况:因此,如果您定义了一个 DB 和一个 APP,则在这种情况下,该应用程序必须引用:psql -U USER -h database -p 5432 DATABASE 如果我被放入容器中,则来自容器内 @Fallenreaper 如果您在容器中并且 docker compose 您将使用该名称,如果您没有明确地给它一个名称,则在“服务:”下使用。因此,在示例中,如果您尝试从 shell 中的“db”容器连接,您将使用“webserver”。查看 db.yml 的示例,您将使用名称 webserver 和 db。抱歉耽搁了,忘记了通知。【参考方案3】:

你必须通过主机的ip访问db,或者如果你想通过localhost:1521访问它,然后像运行webserver -

docker run --net=host --name oracle-wls wls-image:latest

See here

【讨论】:

这将如何在现实生活中发挥作用,因为主机的 ip 将根据正在运行的机器容器而变化。 只有当机器有静态IP或DNS时才有效,否则使用第二种方法。 我似乎对此有疑问。我的确切运行命令是: docker run --name ora-tools-wls -it -p 7001:7001 orawls 这有效,让我以localhost:7001/console 访问我在此容器上运行的服务器但是,来自服务器的数据库访问需要准确的 ip到达另一个运行数据库的容器。如果我使用 docker run --name ora-tools-wls -it -p 7001:7001 --network="host" orawls 则服务器可以使用 localhost 作为 ip 访问数据库,如您所提到的,但可以在主机浏览器中访问服务器失败。 您不需要定义-p 7001:7001,因为所有容器都在使用主机的网络堆栈本身。 @Vik ,我遇到了同样的麻烦,发现它在 mac 上不受支持。也许这也是你正在做的事情。 > 主机网络驱动仅适用于 Linux 主机,不适用于 Docker Desktop for Mac、Docker Desktop for Windows 或 Docker EE for Windows Server。 docs.docker.com/network/host【参考方案4】:

使用docker-compose,默认情况下,服务通过名称相互公开。 Docs. 您还可以指定一个别名,例如;

version: '2.1'
services:
  mongo:
    image: mongo:3.2.11
  redis:
    image: redis:3.2.10
  api:
    image: some-image
    depends_on:
      - mongo
      - solr
    links:
      - "mongo:mongo.openconceptlab.org"
      - "solr:solr.openconceptlab.org"
      - "some-service:some-alias"

然后使用指定的别名作为主机名访问服务,例如mongo.openconceptlab.org 在这种情况下为mongo

【讨论】:

感谢您拍摄文档! :)【参考方案5】:

您可以使用默认的 docker 网络。如果你不想通过任何 docker 网络,你可以这样做:

在Mac的Docker Preferences中的Resources>Network中复制Docker子网中的IP地址: Docker preferences screenshot

从截图链接可以看出,ip地址是

192.168.65.0

您只需将容器配置文件中的“localhost”替换为“192.168.65.1”(即选择的 IP 地址 + 1)。

您可以启动您的容器,并且应该设置为本地开发/测试。

更多细节可以看我的文章: Connect Docker containers the easy way

【讨论】:

【参考方案6】:

考虑示例 我们在这里创建两个容器 PostgreSQL serverpgadmin(用于访问 PHPMyAdmin、SQL studio、workbench 等服务器)。

暴露端口

    PostgreSql --->5436 Pgadmin --->5050

在 pgadmin 主机名中添加一个服务器后作为 localhost。它会显示连接错误。因为 Docker 容器 pgadmin 将 localhost 作为他们的系统,我们需要 PostgreSQL IP 来解决问题。

docker network create con
docker network connect con app1
docker network connect con app2

此命令获取连接的容器 IP 地址和其他详细信息。

docker network inspect con

现在您可以看到网络检查中显示的 IP 地址。选择 Postgres 容器 IP。您可以通过此 IP 访问其他公开的端口。这里只暴露了postgre 5432。现在把hostname设置为容器ip就可以了。

【讨论】:

【参考方案7】:

环境:Windows 10,Docker 桌面版本 4.5.1。

使用主机名host.docker.internal 从容器内部访问在您的主机上运行的服务。

见:https://docs.docker.com/desktop/windows/networking/#use-cases-and-workarounds

我在一个容器中运行 PostgreSQL,在一个单独的容器中运行我的应用程序。 我将应用程序数据库连接配置为使用host.docker.internal 作为主机名,它就可以正常工作。

【讨论】:

以上是关于从另一个容器访问 docker 容器的主要内容,如果未能解决你的问题,请参考以下文章

mac的docker:从另一个容器访问mongo

从另一个 Docker 访问一个 Docker 中的 MariaDB

从另一个容器调用 docker 容器

从另一个容器(Docker)连接到 postgresql 容器

无法从另一个容器连接到 mongodb docker 容器

音频文件未从另一个 docker 容器播放