docker-compose整合go-kit和mysql、Redis
专栏之前有使用go-kit、gorm、go-Redis,所以部分内容就忽略。
定义model 主要实现SelectByEmail(查找)和Save(新建)两个方法:
package modelimport "time" type UserEntity struct { ID int64 Username string Password string Email string CreatedAt time.Time } func (UserEntity) TableName() string { return "user" } type UserDao interface { SelectByEmail(email string ) (*UserEntity, error ) Save(user *UserEntity) error } type UserDaoImpl struct {}func (u *UserDaoImpl) SelectByEmail(email string ) (*UserEntity, error ) { user := &UserEntity{} err := db.Where("email = ?" , email).First(user).Error return user, err } func (u *UserDaoImpl) Save(user *UserEntity) error { return db.Create(user).Error }
业务service package serviceimport ( "context" "demo7-docker-compose/model" "errors" "log" "time" "github.com/jinzhu/gorm" ) type UserInfoDTO struct { ID int64 `json:"id"` Username string `json:"username"` Email string `json:"email"` } var ( ErrUserExisted = errors.New("user is existed" ) ErrPassword = errors.New("email and password are not match" ) ErrRegistering = errors.New("email is registering" ) ) type RegisterUser struct { Username string Password string Email string } type UserService interface { Login(ctx context.Context, email, pass string ) (*UserInfoDTO, error ) Register(ctx context.Context, user *RegisterUser) (*UserInfoDTO, error ) } type UserServiceImpl struct { userDao model.UserDao } func MakeUserServiceImpl (userDao model.UserDao) UserService { return &UserServiceImpl{ userDao, } } func (userService *UserServiceImpl) Login(ctx context.Context, email, password string ) (*UserInfoDTO, error ) { user, err := userService.userDao.SelectByEmail(email) if err == nil { if user.Password == password { return &UserInfoDTO{ ID: user.ID, Username: user.Username, Email: user.Email, }, nil } else { return nil , ErrPassword } } else { log.Printf("err : %s" , err) } return nil , err } func (userService UserServiceImpl) Register(ctx context.Context, user *RegisterUser) (*UserInfoDTO, error ) { ret := model.RedisClient.SetNX(user.Email, 1 , time.Duration(5 )*time.Second) if ret.Val() == false { return nil , ErrRegistering } defer model.RedisClient.Del(user.Email) existUser, err := userService.userDao.SelectByEmail(user.Email) if (err == nil && existUser == nil ) || err == gorm.ErrRecordNotFound { newUser := &model.UserEntity{ Username: user.Username, Password: user.Password, Email: user.Email, } err = userService.userDao.Save(newUser) if err == nil { return &UserInfoDTO{ ID: newUser.ID, Username: newUser.Username, Email: newUser.Email, }, nil } } if err == nil { err = ErrUserExisted } return nil , err }
此处注意分布式锁的实现,利用了Redis的setnx方法,并可以设置过期时间,对应Redis中的
SET key value [EX seconds] [PX milliseconds] [NX|XX]
ret := model.RedisClient.SetNX(user.Email, 1, time.Duration(5)*time.Second) if ret.Val() == false { return nil, ErrRegistering } defer model.RedisClient.Del(user.Email)
对于endpoint和transport,就与之前的没有太大差别了,我们这里就暂时略去,有兴趣可点击文章最后的源码查看。
mysql和Redis容器 mysql的Dockerfile:
FROM mysql:5.7 WORKDIR /docker-entrypoint-initdb.d ENV LANG=C.UTF-8 COPY user.sql .
运行mysql-for-user容器
docker run -itd --name mysql-for-user -p 3316:3306 -e MYSQL_ROOT_PASSWORD=111111 mysql-for-user
这里容器启动的时候是可以执行user.sql的。(可通过docker logs mysql-for-user查看容器启动信息)
/usr/local/bin/docker-entrypoint.sh: running /docker-entrypoint-initdb.d/user.sql
Redis容器的启动简单
docker pull Redis:5.0 docker run -itd --name Redis5 -p 6389:6379 Redis:5.0
然后我们可以运行主程序,智能到8089端口:
go run main.go -service.port 8089
测试一下。
可以实现登录与注册功能。
打包会员镜像 先编译:
CGO_ENABLED=0 GOOS=linux GOARCH=amd64 go build -o user .
user的dockerfile
FROM alpine:3.12 WORKDIR / COPY ./user / ENTRYPOINT ["./user" ]
构建镜像:
docker build -t user-alpine .
docker-compose version: '2.1' services: user13: image: user -alpine depends_on: - Redis - mysql ports: - "8088:8088" links: - Redis - mysql networks: - user mysql: image: mysql-for-user ports: - "3306:3306" expose : - "3306" environment: - MYSQL_ROOT_PASSWORD=111111 networks: - user restart: always Redis: image: Redis:5.0 ports: - "6379:6379" expose : - "6379" networks: - user networks: user : driver: bridge
说明:
depends_on 依赖,此处表示user13依赖Redis、mysql,被依赖者会优先构建,但是是可能脚本为运行成功的,所以user13是有可能刚开始连接不上mysql的,docker start即可
links 连接,此处user13连接到Redis、mysql,可以用它们替代连接数据库的host
environment 环境变量
expose 对links暴露的端口
运行docker-compose up即可。
可以看见服务运行成功了。wow~
dcoker composer语法可看菜鸟教程:
Docker Compose | 菜鸟教程
文中部分知识来自《Go微服务实战38讲》,有兴趣可前往查看: