从 docker 容器(linux 上的 docker)访问主机 postgresql

Posted

技术标签:

【中文标题】从 docker 容器(linux 上的 docker)访问主机 postgresql【英文标题】:Accessing host postgresql from docker container (docker on linux) 【发布时间】:2019-08-08 22:07:04 【问题描述】:

我有一个 spring-boot java 应用程序在我的 linux 主机上的 docker 容器中运行。 我在要从正在运行的容器连接到的主机上安装了一个 postgresql 实例。

我尝试了多种不同的方法(--network="host" 不是我想要的)。

我的 Dockerfile 看起来像这样:

FROM openjdk:13-ea-9-jdk-alpine3.9
EXPOSE 8080
CMD mkdir /opt/StatisticalRestService
COPY target/StatisticalRestService-0.0.1-SNAPSHOT.jar         
/opt/StatisticalRestService/
COPY DockerConfig/application.yml /opt/StatisticalRestService/
RUN chmod 777 /opt/StatisticalRestService/StatisticalRestService-0.0.1-SNAPSHOT.jar \
&& ls -l /opt/StatisticalRestService/StatisticalRestService-0.0.1-SNAPSHOT.jar \
&& INTERNAL_HOST_IP=$(ip route show default | awk '/default/ print $3') \
&& echo "$INTERNAL_HOST_IP  host.docker.internal" >> /etc/hosts \
&& chmod +r /etc/hosts \
&& cat /etc/hosts 
ENTRYPOINT [ "java", "-jar", "-Dspring.config.location=/opt/StatisticalRestService/application.yml", "/opt/StatisticalRestService/StatisticalRestService-0.0.1-SNAPSHOT.jar" ] 

application.yml:

spring:
    application:
        name: StatisticalRestService
    jpa:
        database: POSTGRESQL
        show-sql: true
        hibernate:
            ddl-auto: create-drop
    datasource:
        platform: postgres
        #url: jdbc:postgresql://host.docker.internal:5432/StatisticalRestService
        url: jdbc:postgresql://172.17.0.1:5432/StatisticalRestService
        username: statEntityUser
        password: test123
        driverClassName: org.postgresql.Driver

我已经配置了 postresql 的设置 listen_addressess = '*' 并且以下条目在 pg_hba.conf 中:

host    all     all     172.17.0.0/16       md5
host    all     all     192.168.1.0/24      md5

ifconfig docker0:

arizon@tuxpad:~/Utveckling/StatisticalRestService$ ifconfig
docker0: flags=4099<UP,BROADCAST,MULTICAST>  mtu 1500
    inet 172.17.0.1  netmask 255.255.0.0  broadcast 172.17.255.255
    inet6 fe80::42:3bff:fe4f:ed34  prefixlen 64  scopeid 0x20<link>
    ether 02:42:3b:4f:ed:34  txqueuelen 0  (Ethernet)
    RX packets 28  bytes 1506 (1.5 KB)
    RX errors 0  dropped 0  overruns 0  frame 0
    TX packets 198  bytes 25515 (25.5 KB)
    TX errors 0  dropped 0 overruns 0  carrier 0  collisions 0

这是构建输出:

arizon@tuxpad:~/Utveckling/StatisticalRestService$ sudo docker build . -t arizon/statisticalrestservice:1.0.0-SNAPSHOT
Sending build context to Docker daemon  223.7MB
Step 1/7 : FROM openjdk:13-ea-9-jdk-alpine3.9
---> 6a6c49978498
Step 2/7 : EXPOSE 8080
---> Running in df7ebc70e950
Removing intermediate container df7ebc70e950
---> 417e50a9f5fd
Step 3/7 : CMD mkdir /opt/StatisticalRestService
---> Running in f33ca0acddf7
Removing intermediate container f33ca0acddf7
---> 59ae394176f3
Step 4/7 : COPY target/StatisticalRestService-0.0.1-SNAPSHOT.jar /opt/StatisticalRestService/
---> 4fbcfeb039f8
Step 5/7 : COPY DockerConfig/application.yml /opt/StatisticalRestService/
---> 244d31fc4755
Step 6/7 : RUN chmod 777 /opt/StatisticalRestService/StatisticalRestService-0.0.1-SNAPSHOT.jar && ls -l /opt/StatisticalRestService/StatisticalRestService-0.0.1-SNAPSHOT.jar && INTERNAL_HOST_IP=$(ip route show default | awk '/default/ print $3') && echo "$INTERNAL_HOST_IP  host.docker.internal" >> /etc/hosts && chmod +r /etc/hosts && cat /etc/hosts
---> Running in 241f43aebbdc
-rwxrwxrwx    1 root     root      35266534 Mar 16 19:52 /opt/StatisticalRestService/StatisticalRestService-0.0.1-SNAPSHOT.jar
127.0.0.1   localhost
::1 localhost ip6-localhost ip6-loopback
fe00::0 ip6-localnet
ff00::0 ip6-mcastprefix
ff02::1 ip6-allnodes
ff02::2 ip6-allrouters
172.17.0.2  241f43aebbdc
172.17.0.1  host.docker.internal
Removing intermediate container 241f43aebbdc
---> 5c6c53d8011d
Step 7/7 : ENTRYPOINT [ "java", "-jar", "-Dspring.config.location=/opt/StatisticalRestService/application.yml", "/opt/StatisticalRestService/StatisticalRestService-0.0.1-SNAPSHOT.jar" ]
---> Running in 213a87164e8f
Removing intermediate container 213a87164e8f
---> 802cd987771f
Successfully built 802cd987771f
Successfully tagged arizon/statisticalrestservice:1.0.0-SNAPSHOT

当我使用指向 host.docker.internal 的数据源 url 运行它时,我得到了 unknownHostException,尽管 /etc/hosts 文件的输出确认它在那里。据我了解,alpine 下的 /etc/nsswitch.conf 可能存在问题。我已经尝试添加文件并从我的主机粘贴这一行:

hosts:          files mdns4_minimal [NOTFOUND=return] dns myhostname

无济于事。

当我使用指向 172.17.0.1:5432 的数据源 url 运行它时,我得到连接超时。

我通过将 pgadmin 指向 192.168 ip 来验证从主机访问 psql 以验证 listen_addresses = '*' 是否有效:

host    all     all     192.168.1.0/24      md5

确实如此。这是一个不同的条目。

Docker 版本:

Client:
 Version:           18.09.2
 API version:       1.39
 Go version:        go1.10.4
 Git commit:        6247962
 Built:             Tue Feb 26 23:52:23 2019
 OS/Arch:           linux/amd64
 Experimental:      false

Server:
 Engine:
  Version:          18.09.2
  API version:      1.39 (minimum version 1.12)
  Go version:       go1.10.4
  Git commit:       6247962
  Built:            Wed Feb 13 00:24:14 2019
  OS/Arch:          linux/amd64
  Experimental:     false

PostgreSQL 版本:

arizon@tuxpad:~/Utveckling/StatisticalRestService$ dpkg --list | grep postgresql
ii  postgresql-10                                               10.6-0ubuntu0.18.04.1               amd64        object-relational SQL database, version 10 server

所以,TL;DR:两个问题: 1. 如何让host.docker.internal在linux下的docker上工作? 2. 如何将我的容器化应用程序连接到我的主机 postgresql 实例?

【问题讨论】:

听起来是事实,但您是否在 docker 文件中尝试过 EXPOSE 5432 @daark 是的,但似乎 EXPOSE 更像是一个纪录片设置。运行容器时的 -p 标志很重要。我尝试同时执行 -p 8081:8080 和 -p 5432:5432,没有区别。 【参考方案1】:

我没有按照我提出问题时的预期方式解决了这个问题,但它已经解决了。

我最终也创建了一个带有卷的 postgres 容器,以保持持久数据的持久性。

我为 postgres 制作了一个 Dockerfile,如下所示:

FROM postgres:10-alpine
RUN mkdir /docker-entrypoint-initdb.d/
#COPY initdb.sql /docker-entrypoint-initdb.d/
COPY my-postgres.conf /usr/local/share/postgresql/postgresql.conf
#ENV POSTGRES_USER statEntityUser
#ENV POSTGRES_PASSWORD test123
#ENV POSTGRES_DB StatisticalRestService
ENTRYPOINT ["docker-entrypoint.sh"]
EXPOSE 5432
CMD [ "postgres" ]

initdb.sql 脚本只是创建与注释环境变量相同的东西,即用户、密码和数据库。当数据库启动并准备就绪时,放置在该文件夹中的 Sql-scripts 由入口点脚本运行(它是我从中派生的 docker 映像中的一个开箱即用的功能)。它们被注释掉的原因是它在 docker-compose 文件中(见下文)。 postgresql.conf 基本上是包含在容器中的模板,但listen_addresses = '*' 未注释。

我还制作了一个 docker-compose.yml 来很好地同时运行这两个容器:

version: "3"
services:
  statistical-rest-service:
    build: ./StatisticalRestService
    ports: 
      - 8081:8080
    depends_on:
      - postgres
    networks:
      - statisticsNet
  postgres:
    container_name: postgres
    build: ./Postgres
    ports:
      - 5433:5432
    volumes:
      -  postgres-volume:/var/lib/postgresql/data
    command: postgres -c 'config_file=/usr/local/share/postgresql/postgresql.conf'
    networks:
      - statisticsNet
    environment:
      POSTGRES_USER: statEntityUser
      POSTGRES_PASSWORD: test123
      POSTGRES_DB: StatisticalRestService
networks:
  statisticsNet:
volumes:
  postgres-volume:

我不确定你是否必须事先创建卷,或者它是否包含在 docker-compose 中,但如果你需要,它只是 docker volume create postgres-volume

关于如何使用图像和/或从中派生图像的 Postgres 文档:Postgres on docker hub 注意: 当你用指定的卷启动容器时,犯一些错误并关闭它,当你再次启动它时,它不会与卷上现有的数据库发生冲突。您可能会陷入“悬空卷”的位置,这些卷是您已杀死并删除的旧运行时容器的陈旧版本,但它们可能会产生意外行为(对我而言,未创建用户和数据库是因为这)。 您可以使用以下命令清除它们:docker volume rm $(docker volume ls -qf dangling=true)(或在 $() 中运行命令以列出最终的悬空卷。

由于我在 docker-compose 文件中创建了一个专用的 docker 网络,因此容器可以通过名称找到彼此(注意 container_name)。这使得我的 java 的 application.yml 中的连接 url 如下所示:url: jdbc:postgresql://postgres:5432/StatisticalRestService

我希望有人对此有所帮助:)

【讨论】:

以上是关于从 docker 容器(linux 上的 docker)访问主机 postgresql的主要内容,如果未能解决你的问题,请参考以下文章

docker入门之镜像管理基础

Docke--基础篇

Docke及Docker Compose于微服务的实践

浅谈Windows与Linux环境中的Docker容器

linux下docker启动nginx无法访问80端口

Docker网络与Iptables浅析