今天打算使用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。