对于我的应用程序,有一个运行 Cassandra 的 Docker 容器
database
。我向主机公开了端口 9160
和 9042
,但由于某种原因,我无法从主机连接到 Cassandra。我可以使用 cqlsh
从其他 Docker 容器连接到它,只要我将其他容器放在同一个网络中。
我的
docker-compose
文件(我使用 docker-compose up
运行):
database:
image: cassandra
container_name: database
depends_on:
- kafka
ports:
- 9042:9042
- 9160:9160
volumes:
- ./:/code
environment:
- CASSANDRA_START_RPC=true
- CASSANDRA_BROADCAST_ADDRESS=database
entrypoint: "/code/scripts/cassandra.sh"
frontend:
container_name: frontend
build:
context: driver/
volumes:
- ./:/code
network_mode: service:database
environment:
- BOOTSTRAP_SERVER=kafka:9092
- CASSANDRA_HOST=localhost
entrypoint: "/code/scripts/frontend.sh"
其中
cassandra.sh
和 frontend.sh
只需通过运行脚本并分别安装一些软件包来初始化数据库。
使用上述设置,我只需在
cqlsh
容器中调用 frontend
即可使用 cqlsh。但是,如果我从 network_mode: service:database
中删除线 frontend
,并尝试使用 cqlsh database
或 cqlsh $CASSANDRA_HOST
进行连接,即使在我设置了 CASSANDRA_HOST=database
之后也是如此。执行上述任何命令都会给我:
Connection error: ('Unable to connect to any servers', {'172.27.0.5:9042': ConnectionRefusedError(111, "Tried connecting to [('172.27.0.5', 9042)]. Last error: Connection refused")})
.
因此,即使我公开了端口 9042,我也无法从主机运行
cqlsh
。主机是运行 macOS Monterey 12.3.1 的 2020 iMac。:
> netstat -anvp tcp | awk 'NR<3 || /LISTEN/'
Active Internet connections (including servers)
Proto Recv-Q Send-Q Local Address Foreign Address (state) rhiwat shiwat pid epid state options
tcp46 0 0 *.29092 *.* LISTEN 131072 131072 911 0 0x0100 0x00000006
tcp4 0 0 127.0.0.1.9042 *.* LISTEN 131072 131072 7099 0 0x0100 0x00000006
tcp4 0 0 127.0.0.1.7000 *.* LISTEN 131072 131072 7099 0 0x0100 0x00000006
tcp4 0 0 127.0.0.1.54196 *.* LISTEN 131072 131072 7099 0 0x0100 0x00000006
tcp4 0 0 127.0.0.1.7199 *.* LISTEN 131072 131072 7099 0 0x0100 0x00000006
tcp46 0 0 *.8080 *.* LISTEN 131072 131072 911 0 0x0100 0x00000006
tcp46 0 0 *.7077 *.* LISTEN 131072 131072 911 0 0x0100 0x00000006
tcp46 0 0 *.4040 *.* LISTEN 131072 131072 911 0 0x0100 0x00000006
tcp46 0 0 *.9160 *.* LISTEN 131072 131072 911 0 0x0100 0x00000006
tcp46 0 0 *.9042 *.* LISTEN 131072 131072 911 0 0x0100 0x00000006
tcp46 0 0 *.2181 *.* LISTEN 131072 131072 911 0 0x0100 0x00000006
tcp4 0 0 127.0.0.1.6463 *.* LISTEN 131072 131072 1241 0 0x0100 0x00000106
tcp4 0 0 127.0.0.1.49390 *.* LISTEN 131072 131072 826 0 0x0100 0x00000106
tcp4 0 0 127.0.0.1.45623 *.* LISTEN 131072 131072 826 0 0x0100 0x00000106
tcp4 0 0 127.0.0.1.49380 *.* LISTEN 131072 131072 826 0 0x0100 0x00000106
tcp4 0 0 127.0.0.1.49379 *.* LISTEN 131072 131072 826 0 0x0100 0x00000106
tcp4 0 0 127.0.0.1.15292 *.* LISTEN 131072 131072 770 0 0x0000 0x0000020f
tcp6 0 0 *.5000 *.* LISTEN 131072 131072 465 0 0x0100 0x00000006
tcp4 0 0 *.5000 *.* LISTEN 131072 131072 465 0 0x0100 0x00000006
tcp6 0 0 *.7000 *.* LISTEN 131072 131072 465 0 0x0100 0x00000006
tcp4 0 0 *.7000 *.* LISTEN 131072 131072 465 0 0x0100 0x00000006
tcp6 0 0 *.49198 *.* LISTEN 131072 131072 494 0 0x0100 0x00000006
tcp4 0 0 *.49198 *.* LISTEN 131072 131072 494 0 0x0100 0x00000006
我花了几个小时寻找解决方案,并查看了 StackOverflow 和其他网站上关于此主题的几乎所有可能的帖子,但没有一个解决方案适合我。我将非常感谢一些帮助。
该问题是由设置入口点引起的:
entrypoint: "/code/scripts/cassandra.sh"
事实证明,如果未提供入口点,某些 Cassandra 设置仅由图像初始化。如果提供了,您必须自己设置这些设置,而我没有这样做。我添加了入口点
cassandra.sh
,因为我想通过运行文件来初始化数据库 create.cql
:
#!/bin/sh
cassandra -R
# Wait for Cassandra to start up
while ! cqlsh -e 'describe cluster' ; do
sleep 1
done
echo "Cassandra has started"
cqlsh --file '/code/scripts/create.cql'
echo "Cassandra has been initialised"
tail -f /dev/null
我最终创建了另一个 Docker 容器,它在数据库启动后简单地初始化数据库:
database:
image: cassandra
container_name: database
depends_on:
- kafka
ports:
- 9042:9042
- 9160:9160
volumes:
- ./:/code
db_seeder:
container_name: db_seeder
build:
context: db_seeder/
depends_on:
- database
volumes:
- ./:/code
environment:
- CASSANDRA_HOST=database
entrypoint: "/code/scripts/cassandra.sh"
解决方案
命令 “docker pull cassandra:latest” 正在利用容器化平台 Docker 从官方 Docker Hub 存储库下载最新版本的 Cassandra 数据库管理系统 (DBMS) 映像。用技术术语来说:
Docker: 一个平台,使开发人员能够将应用程序及其依赖项打包到轻量级、可移植的容器中。容器在不同环境中提供一致的环境,使部署和扩展应用程序变得更加容易。
pull: 此 Docker 命令用于从容器注册表中获取容器映像。在本例中,它正在拉取 Cassandra 映像。
cassandra:latest: 指定要拉取的镜像。 “cassandra”是 Cassandra DBMS 的 Docker 映像的名称,“:latest”表示应检索映像的最新可用版本。
Docker Hub:基于云的注册表服务,Docker 用户可以在其中共享和访问容器映像。官方 Cassandra 镜像托管在 Docker Hub 上。
因此,当您运行 “docker pull cassandra:latest”时, Docker 将从 Docker Hub 下载最新版本的 Cassandra 映像,使其可在您的计算机上本地使用。 docker pull cassandra:最新
现在命令:
docker run --name cassandra -p 127.0.0.1:9042:9042 -p 127.0.0.1:9160:9160 -d cassandra
您提供的命令是用于运行 Cassandra 容器的 Docker 命令。让我们用技术术语来分解一下:
docker run:该命令用于根据指定镜像创建并启动一个新的容器。
--name cassandra: 为新创建的容器分配名称“cassandra”。这对于在后续 Docker 命令中引用容器很有帮助。
-p 127.0.0.1:9042:9042: 将容器的端口 9042(Cassandra 的本机传输端口)映射到主机的端口 9042。这意味着您可以在主机上通过 127.0.0.1:9042 访问 Cassandra。
-p 127.0.0.1:9160:9160: 将容器的端口 9160(用于 Thrift 通信)映射到主机的端口 9160。这允许您在主机上使用 Thrift 与 Cassandra 交互(地址为 127.0.0.1:9160) .
-d: 在后台运行容器(分离模式),允许您继续使用终端。
cassandra:指定用于创建容器的 Docker 映像的名称。在本例中,它是 Cassandra 图像。
因此,当您运行命令 “docker run --name cassandra -p 127.0.0.1:9042:9042 -p 127.0.0.1:9160:9160 -d cassandra”时,它会启动一个具有指定端口映射的新 Cassandra 容器,使 Cassandra 在主机上提供的端口上可访问。
使用此命令将导致 (com.datastax.driver.core.exceptions.TransportException: [/127.0.0.1:9042] Cannot connect))异常像魔法一样消失!