不同docker容器应用访问同一个docker镜像数据库
场景描述:
以本人自己服务器上的应用举例,我首先部署的是halo+mysql应用,按照官网给出的 docker-compose.yml
文件示意,我是这么写的。
version: "3"
services:
halo:
image: halohub/halo:2.11
container_name: halo
restart: on-failure:3
depends_on:
halodb:
condition: service_healthy
networks:
halo_network:
volumes:
- ./halo2:/root/.halo2
ports:
- "8090:8090"
healthcheck:
test: ["CMD", "curl", "-f", "http://localhost:8090/actuator/health/readiness"]
interval: 30s
timeout: 5s
retries: 5
start_period: 30s
command:
- --spring.r2dbc.url=r2dbc:pool:mysql://halodb:3306/halo
- --spring.r2dbc.username=root
# MySQL 的密码,请保证与下方 MYSQL_ROOT_PASSWORD 的变量值一致。
- --spring.r2dbc.password=o#DwN&JSa56
- --spring.sql.init.platform=mysql
# 外部访问地址,请根据实际需要修改
- --halo.external-url=http://localhost:8090/
halodb:
image: mysql:8.1.0
container_name: halodb
restart: on-failure:3
networks:
halo_network:
command:
- --default-authentication-plugin=caching_sha2_password
- --character-set-server=utf8mb4
- --collation-server=utf8mb4_general_ci
- --explicit_defaults_for_timestamp=true
volumes:
- ./mysql:/var/lib/mysql
- ./mysqlBackup:/data/mysqlBackup
ports:
- "3306:3306"
healthcheck:
test: ["CMD", "mysqladmin", "ping", "-h", "127.0.0.1", "--silent"]
interval: 3s
retries: 5
start_period: 30s
environment:
# 请修改此密码,并对应修改上方 Halo 服务的 SPRING_R2DBC_PASSWORD 变量值
- MYSQL_ROOT_PASSWORD=o#DwN&JSa56
- MYSQL_DATABASE=halo
networks:
halo_network:
当时的机器纯净的就像一张白纸,写完按照命令启动,执行:
docker-compose up -d
OK,没有一点问题。
后来过了几个月,我又想部署一个私人的代码管理器,选来选去选到了 gitea
这个项目。开源、免费、轻量,very nice,完美符合我的要求。
部署的时候就有一点点问题了,官网给的 docker-compose.yml
文件是这样的。
version: "3"
networks:
gitea:
external: false
services:
server:
image: gitea/gitea:1.21.4
container_name: gitea
environment:
- USER_UID=1000
- USER_GID=1000
+ - GITEA__database__DB_TYPE=mysql
+ - GITEA__database__HOST=db:3306
+ - GITEA__database__NAME=gitea
+ - GITEA__database__USER=gitea
+ - GITEA__database__PASSWD=gitea
restart: always
networks:
- gitea
volumes:
- ./gitea:/data
- /etc/timezone:/etc/timezone:ro
- /etc/localtime:/etc/localtime:ro
ports:
- "3000:3000"
- "222:22"
+ depends_on:
+ - db
+
+ db:
+ image: mysql:8
+ restart: always
+ environment:
+ - MYSQL_ROOT_PASSWORD=gitea
+ - MYSQL_USER=gitea
+ - MYSQL_PASSWORD=gitea
+ - MYSQL_DATABASE=gitea
+ networks:
+ - gitea
+ volumes:
+ - ./mysql:/var/lib/mysql
问题来了,我已经部署了一个mysql镜像了,完全没必要再装另外一个呀,那怎么办呢,我当时的解决思路简单粗暴,把 gitea
的配置文件和之前halo的写一块不就得了,直接使用 halo
部署的 mysql
数据库。OK,简单直接粗暴。
配置文件杂乱
过了一阵我又想搭建一个图床应用,使用的是比较主流的图床应用兰空图床,他也要配置一个数据库,这我可坐不住了,没道理的,配置文件写一块吧,显得 docker-compose.yml
文件杂乱无章,不同的应用都部署到一块,不写吧,可是我又不想再 pull
一个 mysql
的镜像,我的服务器本就不富裕。
网上搜索无果的情况下(也可能是我搜索的姿势不对)。我去问了问百度的文心一言。还是有惊喜的。下面是文心一言的回答。
问:我已经使用docker安装了数据库,如何在其他的docker-compose文件如何使用已经部署好的数据库?
答:要在一个Docker Compose文件中连接到已经在另一个Docker Compose文件中运行的数据库,你可以通过定义链接或使用环境变量来实现。以下是两种方法:
- 使用链接:
假设你有两个Compose文件,一个用于数据库,另一个用于其他服务。
# docker-compose-db.yml version: '3' services: db: image: mysql:5.7 container_name: db ports: - "3306:3306" environment: MYSQL_ROOT_PASSWORD: password MYSQL_DATABASE: mydb MYSQL_USER: myuser MYSQL_PASSWORD: mypass
对于其他服务,你可以在docker-compose.yml中链接到数据库服务:
# docker-compose.yml version: '3' services: web: image: nginx:latest container_name: web ports: - "8080:80" links: - db:db_host environment: DB_HOST: db_host DB_NAME: mydb DB_USER: myuser DB_PASSWORD: mypass
- 使用环境变量:
如果你不使用链接,你可以通过环境变量来传递数据库的连接信息。首先,在数据库的Compose文件中定义环境变量:
# docker-compose-db.yml version: '3' services: db: image: mysql:5.7 container_name: db ports: - "3306:3306" environment: MYSQL_ROOT_PASSWORD: password MYSQL_DATABASE: mydb MYSQL_USER: myuser MYSQL_PASSWORD: mypass networks: - my_network
然后,在另一个Compose文件中,使用
external
网络并连接到同一个网络:# docker-compose.yml version: '3' services: web: image: nginx:latest container_name: web ports: - "8080:80" environment: DB_HOST: db_host DB_NAME: mydb DB_USER: myuser DB_PASSWORD: mypass networks: - my_network networks: my_network: external: true
在上面的例子中,
web
服务会连接到db
服务所在的同一网络,并且可以从该服务中获取环境变量。这允许你在web
服务中连接到数据库。
讲道理,第一种方法我没有成功,但是第二种方法确确实实是可行的
我思考了一下,访问不到数据库的原因大概就是不在同一个网段内吧,按照第二种方法来讲,其实是把数据库和图床两个应用的网络放到了同一个网段,所以就可以访问到了。
额外的收获是还学会了docker的一个命令:docker inspect xxxxxxxxx | grep IPAdress
其中一串x的是容器的容器id,这样就可以查看某个容器被docker分配的ip地址了。