从 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的主要内容,如果未能解决你的问题,请参考以下文章