Bootstrap

docker-compose部署服务网络通信问题

今天打算使用docker-compose 部署下服务器,本来以为很快可以完成,但是竟然滑铁卢,mysql8.0容器可以正常启动,但是go项目文件却怎么也连不上mysql容器,以下是事故现场和配置文件.解决方案在步骤里。

docker-compose logs mysql部分:
在这里插入图片描述
go项目部分:
在这里插入图片描述
docker-compose 文件如下:

version: '3.5'
services:
  stargate:
    image: ubuntu:18.04
    restart: always
    working_dir: /stargate
    volumes:
      - ./stargate:/stargate
    ports:
      - 18080:8080
    command: ./stargate dev.yaml
    networks:
      bridge_net:
        ipv4_address: ${BRIDGE_SUBNET_PREFIX}.03
  mysql:
    image: mysql:8.0
    restart: always
    volumes:
      - mysql_data:/var/lib/mysql
    ports:
      - "13306:3306"
    environment:
      - MYSQL_USER= "root"
      - MYSQL_PASSWORD= "123456"
      - MYSQL_ROOT_PASSWORD= "123456"
      - MYSQL_DATABASE= "stargate"
      - MYSQL_ROOT_HOST= "%"
    networks:
      bridge_net:
        ipv4_address: ${BRIDGE_SUBNET_PREFIX}.02
volumes:
  mysql_data: {}
networks:
  bridge_net:
    external: true
    name: ${BRIDGE_NET}

go项目的配置文件dev.yaml如下:

name: "stargate"
mode: "debug"
port: 8080
version: "v0.0.1"
start_time: "2022-08-23"
machine_id: 1
OwnerEmail: "[email protected]"
enableHttps: false

log:
  level: "info"
#  filename: "stargate.log"
#  max_size: 200
#  max_age: 30
#  max_backups: 7
mysql:
  host: mysql
  port: 13306
  user: "root"
  password: "123456"
  dbname: "stargate"
  max_open_conns: 200
  max_idle_conns: 50
~                                                                                                                                                                  
~                                                                                                                                                                  
~  

go项目初始化mysql的代码如下:

// Init 初始化MySQL连接
func Init(cfg *settings.MySQLConfig) (err error) {
	// "user:stargateword@tcp(host:port)/dbname"
	dsn := fmt.Sprintf("%s:%s@tcp(%s:%d)/%s?parseTime=true&loc=Local", cfg.User, cfg.Password, cfg.Host, cfg.Port, cfg.DB)
	db, err = gorm.Open(mysql.Open(dsn))
	if err != nil {
		logger.Lg.Error("mysql connect failed...", zap.Error(err))
		return
	}
	mysqldb, _ := db.DB()
	 全局禁用表名复数
	//mysqldb.SingularTable(true) // 如果设置为true,`User`的默认表名为`user`,使用`TableName`设置的表名不受影响
	mysqldb.SetMaxOpenConns(cfg.MaxOpenConns)
	mysqldb.SetMaxIdleConns(cfg.MaxIdleConns)
	logger.Lg.Info("Init mysql success...")
	InitSYS_DIC()
	logger.Lg.Info("Init SYS_DIC success...")
	return
}

创建网络的命令如下:

docker network create bridge_net --subnet 172.31.0.0/24

.env文件如下:

BRIDGE_SUBNET_PREFIX=172.31.0

BRIDGE_NET=bridge_net

进入mysql容器查看用户和host,可以看到stargate库已经创建,host为%:

oot@ecs-51ff home]# docker exec -it home_mysql_1  mysql -uroot -p
Enter password: 
Welcome to the MySQL monitor.  Commands end with ; or \g.
Your MySQL connection id is 8
Server version: 8.0.30 MySQL Community Server - GPL

Copyright (c) 2000, 2022, Oracle and/or its affiliates.

Oracle is a registered trademark of Oracle Corporation and/or its
affiliates. Other names may be trademarks of their respective
owners.

Type 'help;' or '\h' for help. Type '\c' to clear the current input statement.

mysql> show tables;
ERROR 1046 (3D000): No database selected
mysql> show databases;
+--------------------+
| Database           |
+--------------------+
| information_schema |
| mysql              |
| performance_schema |
| stargate           |
| sys                |
+--------------------+
5 rows in set (0.00 sec)

mysql> use mysql 
Reading table information for completion of table and column names
You can turn off this feature to get a quicker startup with -A

Database changed
mysql> select user,host from user;
+------------------+-----------+
| user             | host      |
+------------------+-----------+
| root             | %         |
| mysql.infoschema | localhost |
| mysql.session    | localhost |
| mysql.sys        | localhost |
| root             | localhost |
+------------------+-----------+
5 rows in set (0.00 sec)

mysql> 

本来也参考了一些文章,在compose文件的mysql配置里加入了这个,结果mysql容器也起不来了。。。。:

 command:
      # default-authentication-plugin=mysql_native_password   mysql5为mysql_native_password, 支持较好, mysql8为默认为caching_sha2_password, 部分旧软件不支持;
      # character-set-server=utf8mb4                          默认创建新数据的新建字符集
      # collation-server=utf8mb4_general_ci                   默认创建新数据的新建排序规则
      # default-time-zone='+8:00'                             选择正8区
      # max_connections=1000                                  设置最大连接数
      # innodb_lock_wait_timeout=500                          innodb的dml操作的行级锁的等待时间
      --default-authentication-plugin=mysql_native_password

-------------------------------------分割线----------------------------------------
本着多试几次的态度,我将–default-authentication-plugin=mysql_native_password 重新加上了,

version: '3.5'
services:
  stargate:
    image: ubuntu:18.04
    restart: always
    working_dir: /stargate
    volumes:
      - ./stargate:/stargate
    ports:
      - 18080:8080
    command: ./stargate dev.yaml
    networks:
      bridge_net:
        ipv4_address: ${BRIDGE_SUBNET_PREFIX}.03
  mysql:
    image: mysql:8.0
    restart: always
    volumes:
      - mysql_data:/var/lib/mysql
    ports:
      - "13306:3306"
    command: --default-authentication-plugin=mysql_native_password
    environment:
      - MYSQL_USER= "root"
      - MYSQL_PASSWORD= "123456"
      - MYSQL_ROOT_PASSWORD= "123456"
      - MYSQL_ROOT_HOST= "%"
    networks:
      bridge_net:
        ipv4_address: ${BRIDGE_SUBNET_PREFIX}.02
volumes:
  mysql_data: {}
networks:
  bridge_net:
    external: true
    name: ${BRIDGE_NET}

因为知道配置网络后容器可以通过容器名访问,于是想到是不是端口也要用内部端口,于是将13306改为了3306,

name: "stargate"
mode: "debug"
port: 8080
version: "v0.0.1"
start_time: "2022-08-23"
machine_id: 1
OwnerEmail: "[email protected]"
enableHttps: false

log:
  level: "info"
#  filename: "stargate.log"
#  max_size: 200
#  max_age: 30
#  max_backups: 7
mysql:
  host: mysql
  port: 3306
  user: "root"
  password: "123456"
  dbname: "stargate"
  max_open_conns: 200
  max_idle_conns: 50

结果竟然成功了。
但是从日志可以看到是有了几次错误之后才成功的。为什么会先错几次才成功,不清楚。

[root@ecs-51ff home]# docker-compose logs
Attaching to home_mysql_1, home_stargate_1
mysql_1     | 2022-09-20 10:05:39+00:00 [Note] [Entrypoint]: Entrypoint script for MySQL Server 8.0.30-1.el8 started.
mysql_1     | 2022-09-20 10:05:39+00:00 [Note] [Entrypoint]: Switching to dedicated user 'mysql'
mysql_1     | 2022-09-20 10:05:39+00:00 [Note] [Entrypoint]: Entrypoint script for MySQL Server 8.0.30-1.el8 started.
mysql_1     | '/var/lib/mysql/mysql.sock' -> '/var/run/mysqld/mysqld.sock'
mysql_1     | 2022-09-20T10:05:39.605717Z 0 [Warning] [MY-011068] [Server] The syntax '--skip-host-cache' is deprecated and will be removed in a future release. Please use SET GLOBAL host_cache_size=0 instead.
mysql_1     | 2022-09-20T10:05:39.606759Z 0 [Warning] [MY-010918] [Server] 'default_authentication_plugin' is deprecated and will be removed in a future release. Please use authentication_policy instead.
mysql_1     | 2022-09-20T10:05:39.606777Z 0 [System] [MY-010116] [Server] /usr/sbin/mysqld (mysqld 8.0.30) starting as process 1
mysql_1     | 2022-09-20T10:05:39.612780Z 1 [System] [MY-013576] [InnoDB] InnoDB initialization has started.
mysql_1     | 2022-09-20T10:05:39.728797Z 1 [System] [MY-013577] [InnoDB] InnoDB initialization has ended.
mysql_1     | 2022-09-20T10:05:39.928952Z 0 [Warning] [MY-010068] [Server] CA certificate ca.pem is self signed.
mysql_1     | 2022-09-20T10:05:39.928986Z 0 [System] [MY-013602] [Server] Channel mysql_main configured to support TLS. Encrypted connections are now supported for this channel.
mysql_1     | 2022-09-20T10:05:39.930906Z 0 [Warning] [MY-011810] [Server] Insecure configuration for --pid-file: Location '/var/run/mysqld' in the path is accessible to all OS users. Consider choosing a different directory.
mysql_1     | 2022-09-20T10:05:39.948930Z 0 [System] [MY-011323] [Server] X Plugin ready for connections. Bind-address: '::' port: 33060, socket: /var/run/mysqld/mysqlx.sock
mysql_1     | 2022-09-20T10:05:39.949005Z 0 [System] [MY-010931] [Server] /usr/sbin/mysqld: ready for connections. Version: '8.0.30'  socket: '/var/run/mysqld/mysqld.sock'  port: 3306  MySQL Community Server - GPL.
stargate_1  | 2022-09-20T10:05:39.076Z  INFO    logger/logger.go:45     init logger success
stargate_1  | 
stargate_1  | 2022/09/20 10:05:39 /Users/hanpeng/Documents/metamarvel/stargate/dao/mysql/mysql.go:22
stargate_1  | [error] failed to initialize database, got error dial tcp 172.31.0.2:3306: connect: connection refused
stargate_1  | 2022-09-20T10:05:39.077Z  ERROR   mysql/mysql.go:24       mysql connect failed... {"error": "dial tcp 172.31.0.2:3306: connect: connection refused"}
stargate_1  | init mysql failed, err:dial tcp 172.31.0.2:3306: connect: connection refused
stargate_1  | 2022-09-20T10:05:39.449Z  INFO    logger/logger.go:45     init logger success
stargate_1  | 
stargate_1  | 2022/09/20 10:05:39 /Users/hanpeng/Documents/metamarvel/stargate/dao/mysql/mysql.go:22
stargate_1  | [error] failed to initialize database, got error dial tcp 172.31.0.2:3306: connect: connection refused
stargate_1  | 2022-09-20T10:05:39.450Z  ERROR   mysql/mysql.go:24       mysql connect failed... {"error": "dial tcp 172.31.0.2:3306: connect: connection refused"}
stargate_1  | init mysql failed, err:dial tcp 172.31.0.2:3306: connect: connection refused
stargate_1  | 2022-09-20T10:05:39.912Z  INFO    logger/logger.go:45     init logger success
stargate_1  | 
stargate_1  | 2022/09/20 10:05:39 /Users/hanpeng/Documents/metamarvel/stargate/dao/mysql/mysql.go:22
stargate_1  | [error] failed to initialize database, got error dial tcp 172.31.0.2:3306: connect: connection refused
stargate_1  | 2022-09-20T10:05:39.913Z  ERROR   mysql/mysql.go:24       mysql connect failed... {"error": "dial tcp 172.31.0.2:3306: connect: connection refused"}
stargate_1  | init mysql failed, err:dial tcp 172.31.0.2:3306: connect: connection refused
stargate_1  | 2022-09-20T10:05:40.577Z  INFO    logger/logger.go:45     init logger success
stargate_1  | 2022-09-20T10:05:40.582Z  INFO    mysql/mysql.go:32       Init mysql success...
stargate_1  | 2022-09-20T10:05:40.590Z  INFO    mysql/mysql.go:34       Init SYS_DIC success...
stargate_1  | 2022-09-20T10:05:40.590Z  ERROR   miniocli/minioInit.go:31        Init minioclient success...
stargate_1  | [GIN-debug] [WARNING] Running in "debug" mode. Switch to "release" mode in production.
stargate_1  |  - using env:     export GIN_MODE=release
stargate_1  |  - using code:    gin.SetMode(gin.ReleaseMode)
stargate_1  | [GIN-debug] GET    /                         --> stargate/router.SetupGinRouter.func1 (2 handlers)
stargate_1  | [GIN-debug] GET    /ping                     --> stargate/router.SetupGinRouter.func2 (2 handlers)
stargate_1  | [GIN-debug] GET    /swagger/*any             --> github.com/swaggo/gin-swagger.CustomWrapHandler.func1 (2 handlers)
stargate_1  | [GIN-debug] POST   /api/kol/add              --> stargate/controller.AddKolHandler (2 handlers)
stargate_1  | [GIN-debug] POST   /api/kol/findkol          --> stargate/controller.FindKolHandler (2 handlers)
stargate_1  | [GIN-debug] GET    /api/kol/ranking          --> stargate/controller.KolRankHandler (2 handlers)
stargate_1  | [GIN-debug] POST   /api/kol/confirm          --> stargate/controller.KolConfirmHandler (2 handlers)
stargate_1  | [GIN-debug] POST   /api/project/add          --> stargate/controller.AddProjectHandler (2 handlers)
stargate_1  | [GIN-debug] POST   /api/project/findproject  --> stargate/controller.FindProjectHandler (2 handlers)
stargate_1  | [GIN-debug] POST   /api/task/add             --> stargate/controller.AddTaskHandler (2 handlers)
stargate_1  | [GIN-debug] POST   /api/task/findtask        --> stargate/controller.FindTaskHandler (2 handlers)
stargate_1  | [GIN-debug] PUT    /api/task/update          --> stargate/controller.TaskUpdateHandler (2 handlers)
stargate_1  | [GIN-debug] GET    /api/task/mytask          --> stargate/controller.MyTaskHandler (2 handlers)
stargate_1  | [GIN-debug] GET    /api/function/system_dic  --> stargate/controller.DictionaryHandler (2 handlers)
stargate_1  | [GIN-debug] POST   /api/function/sendnotice  --> stargate/controller.NoticeHandler (2 handlers)
stargate_1  | [GIN-debug] POST   /api/function/smartmatch  --> stargate/controller.MatchHandler (2 handlers)
stargate_1  | [GIN-debug] GET    /api/function/firstpage   --> stargate/controller.FirstpageHandler (2 handlers)
stargate_1  | [GIN-debug] POST   /api/function/uploadfile  --> stargate/controller.UploadFileHandler (2 handlers)
stargate_1  | [GIN-debug] GET    /api/function/downloadfile --> stargate/controller.DownloadFileHandler (2 handlers)
stargate_1  | [GIN-debug] GET    /debug/pprof/             --> github.com/gin-gonic/gin.WrapF.func1 (2 handlers)
stargate_1  | [GIN-debug] GET    /debug/pprof/cmdline      --> github.com/gin-gonic/gin.WrapF.func1 (2 handlers)
stargate_1  | [GIN-debug] GET    /debug/pprof/profile      --> github.com/gin-gonic/gin.WrapF.func1 (2 handlers)
stargate_1  | [GIN-debug] POST   /debug/pprof/symbol       --> github.com/gin-gonic/gin.WrapF.func1 (2 handlers)
stargate_1  | [GIN-debug] GET    /debug/pprof/symbol       --> github.com/gin-gonic/gin.WrapF.func1 (2 handlers)
stargate_1  | [GIN-debug] GET    /debug/pprof/trace        --> github.com/gin-gonic/gin.WrapF.func1 (2 handlers)
stargate_1  | [GIN-debug] GET    /debug/pprof/allocs       --> github.com/gin-gonic/gin.WrapH.func1 (2 handlers)
stargate_1  | [GIN-debug] GET    /debug/pprof/block        --> github.com/gin-gonic/gin.WrapH.func1 (2 handlers)
stargate_1  | [GIN-debug] GET    /debug/pprof/goroutine    --> github.com/gin-gonic/gin.WrapH.func1 (2 handlers)
stargate_1  | [GIN-debug] GET    /debug/pprof/heap         --> github.com/gin-gonic/gin.WrapH.func1 (2 handlers)
stargate_1  | [GIN-debug] GET    /debug/pprof/mutex        --> github.com/gin-gonic/gin.WrapH.func1 (2 handlers)
stargate_1  | [GIN-debug] GET    /debug/pprof/threadcreate --> github.com/gin-gonic/gin.WrapH.func1 (2 handlers)
stargate_1  | [GIN-debug] [WARNING] You trusted all proxies, this is NOT safe. We recommend you to set a value.
stargate_1  | Please check https://pkg.go.dev/github.com/gin-gonic/gin#readme-don-t-trust-all-proxies for details.
stargate_1  | [GIN-debug] Listening and serving HTTP on :8080

为了测试是否真的连上了数据裤,使用curl做个测试:

[root@ecs-51ff ~]# curl http://127.0.0.1:18080/api/function/firstpage
{"code":200,"msg":"success","data":{"kolnum":7,"projectnum":34,"tournamentsnum":16}}[root@ecs-51ff ~]# 
[root@ecs-51ff ~]# curl -H "Content-Type: application/json" -X POST -d '{"address":[""],"attribute":1}' http://localhost:18080/api/function/sendnotice
{"code":200,"msg":"success"}[root@ecs-51ff ~]# curl -H "Content-Type: application/json" -X POST -d '{"address":[""],"attribute":1}' http://localhost:18080/api/func
[root@ecs-51ff ~]# curl -H "Content-Type: application/json" -X POST -d '{"address":"811","name":"hello","email":"hello","url":"hello url","contact":"119"}' http://localhost:18080/api/project/add
{"code":200,"msg":"success"}[root@ecs-51ff ~]# 

docker exec 进入mysql容器查看是否有新数据添加进来
在这里插入图片描述
真的有数据添加进来。


现在打算down掉,重新测试是哪个配置起了作用.
经过测试并不是command: --default-authentication-plugin=mysql_native_password
这句起了作用。而是正确配置了端口。
于是想到了是否容器外访问就是要127.0.0.1:13306。测试了下依然错误。
所以在go项目的配置文件里 就用docker-compose 里的服务名+容器内端口访问,即:mysql:3306

mysql:
  host: mysql
  port: 3306
  user: "root"
  password: "123456"
  dbname: "stargate"
  max_open_conns: 200
  max_idle_conns: 50

虽然暂时把服务起来了,但是还有几个问题没有解决:
1 连接服务器的时候为啥还会有两次报错?
2 什么原因造成的只能用服务名和内部端口访问?(这个可以归结为对docker-compose 的不熟悉和对原理知识的空缺)
3 貌似compose的文件输入格式还有 : 和 = 的区别 。- 和 – 貌似也有区别。
两个月没弄过docker-compose了 本来自信满满 没想到炸出来这么多知识盲区
求一个熟知docker-compose的大佬来指教指教~~


更新:
docker-compose 起的服务之间不能用127.0.0.1去通信 !
因为这些个服务每个都是独立运行的linux系统 这个时候用127.0.0.1 去通信别的服务 是在这个宿主容器上的127.0.0.1 而不是宿主服务器机的127.0.0.1 所以当然找不到
所以 如果想实现服务间通信 有两种方法:

一是  用公网ip+暴露的外部端口  进行通信 如:94.64.83.175:13306 这在任何条件下 都是可行的
二是  用docker network 相关命令 建立一个服务间的通信网络,即bridge模式的通信网络,在这个网络内 可以直接用 服务名+内部端口 如:mysql:3306 通信

通常来说,
同一台主机的服务之间用内部通信方式最为方便高效,使用内部通信方式即可。
而外部通信的方式则用于与外部公网服务的通信


docker 有三种模式的通信网络
host bridge none
使用host的话 即使用宿主机的网络 不需要代理端口 ,将服务对外暴露,直接就可通信、
同时注意这个时候docker-compose文件里就不需要写port了 ,同时将networks 改为:network_mode: host

version: '3.5'
services:
  stargate:
    image: ubuntu:18.04
    restart: always
    working_dir: /stargate
    volumes:
      - ./stargate:/stargate
    # ports:
    #   - 18181:8181
    command: ./stargate dev.yaml
    network_mode: host

这里另外一个坑要注意就是:host模式用宿主机端口通信 只支持 linux系统。

Host 模式只支持 Linux 系统,Windows 和 macOS 此参数无效。

不支持Docker for Mac,Docker for Windows或Docker EE for Windows Server。
在这里插入图片描述

如Docker For Mac的实现和标准Docker规范有区别,Docker For Mac的Docker Daemon是运行于虚拟机(xhyve)中的, 而不是像Linux上那样作为进程运行于宿主机,因此Docker For Mac没有docker0网桥,不能实现host网络模式,host模式会使Container复用Daemon的网络栈(在xhyve虚拟机中),而不是与Host主机网络栈,这样虽然其它容器仍然可通过xhyve网络栈进行交互,但却不是用的Host上的端口(在Host上无法访问)。bridge网络模式 -p 参数不受此影响,它能正常打开Host上的端口并映射到Container的对应Port。

;