使用Docker Compose搭建Golang✖️Prisma✖️MySQL开发环境!
首先
在进行个人API开发的过程中,我发现自己在懒散地学习Golang的同时,还在寻找一个不错的数据库迁移工具。在进行调查的时候,我发现了一个名为Prisma的工具。据说它可以利用GraphQL进行数据库迁移,并可以作为某些语言中类型安全的ORM工具使用。
在这里,我们将进行开发环境的搭建,详细说明将留给其他文章。然而,由于不想破坏本地环境,所以尽量使用虚拟环境来进行。
容器配置
在Prisma官方网站上有架构的展示。

客户端与API服务器进行交互,API服务器与数据库之间通过Prisma进行连接。如果要在本地环境中复现此过程,我认为会呈现以下图示的形式。

使用Docker Compose可以启动API服务器、Prisma服务器和数据库的三个实例,并且只能通过浏览器访问API服务器。
这意味着无法直接从浏览器访问Prisma服务器和数据库。
在本次的开发环境中,我们会更加灵活地建立,以便更方便进行工作。具体来说,就像下图所示的那样。

最初的图表显示,Prisma Cli的数量正在增加。此外,现在可以访问Prisma服务器。
具体细节将在后文提及,Prisma服务器附带了一个可以从浏览器中进行数据库操作的工具。
在生产环境中,当然不能使用这个工具,但在开发环境中它非常方便,所以我们会打开端口以便可以使用它。
目录结构
最后的目录结构看起来是这样的。
親ディレクトリ
├── api-server
│ └── dockerfile
├── app
│ ├── Gopkg.lock
│ ├── Gopkg.toml
│ ├── datamodel.prisma
│ ├── generated
│ │ └── prisma-client
│ │ └── prisma.go
│ ├── main.go
│ ├── prisma.yml
│ └── vendor
├── docker-compose.yml
└── prisma-cli
└── dockerfile
一般情况下,Golang目录结构与此大为不同,但这样做是为了方便使用Docker Compose进行操作和指定。在常规项目中,建议遵循Golang的规范和思想,采用正确的目录结构。
API服务器的配置
这次没有特别要注意的事项。
因为这次打算使用Golang来搭建API服务器,所以让我们先安装dep以便进行依赖管理。
FROM golang:1.13-alpine3.10
WORKDIR /go/src/app
RUN apk update \
&& apk add git \
&& go get -u github.com/golang/dep/cmd/dep
Prisma命令行工具的设置
Prisma 官方提供了 Cli 工具。
虽然也有在 Homebrew 上发布的版本,但这次我们将使用 npm 库。
FROM node:13.1-alpine3.10
WORKDIR /usr/src/app
RUN npm install -g yarn \
&& yarn global add prisma
Docker Compose的设置
关于Prisma服务器和MySQL,在官方网页上有示例供参考。我们可以参照这些示例来编写。
version: "3"
services:
api-server:
build: ./api-server
container_name: api-server
tty: true
ports:
- "8080:8080"
volumes:
- ./app:/go/src/app
prisma-cli:
build: ./prisma-cli
container_name: prisma-cli
tty: true
volumes:
- ./app:/usr/src/app
prisma-server:
image: prismagraphql/prisma:1.34
container_name: prisma-server
restart: always
ports:
- "4466:4466"
environment:
PRISMA_CONFIG: |
port: 4466
databases:
default:
connector: mysql
host: database
port: 3306
user: root
password: prisma
database:
image: mysql:5.7
container_name: database
environment:
MYSQL_ROOT_PASSWORD: prisma
volumes:
- mysql:/var/lib/mysql
volumes:
mysql: ~
有一些需要注意的地方。
-
- API サーバーと Prisma Cli にtty: trueをつける
API サーバーと Prisma Cli は実行し続けるコマンドを持たないため、起動完了後に停止してしまう
停止したコンテナにはアクセスできないので、停止せずにアクセスできる状態を保つための設定
Prisma サーバーにrestart: alwaysをつける
Prisma サーバーは起動すると DB への接続を試みる
MySQL は起動に時間がかかるため、初回の接続は失敗する
接続失敗するとコンテナが落ちてしまうので、接続できるまで再起動し続けるための設定
一旦設定完畢後,請轉至根目錄並啟動。
$ docker-compose up -d
我们可以通过使用$ docker-compose logs命令来查看启动处理的日志。如果您能从日志中确认Prisma服务器已经启动,请尝试在浏览器中访问localhost:4466。如果可以访问,那就表示一切正常。
对数据库的操作
让我们在构建好的环境中操作数据库。
首先进入Prisma Cli。由于采用了Alpine发行版,所以我们将使用ash,而不是bash。
$ docker-compose exec prisma-cli ash
然后进行项目和数据库的初始化。
$ prisma init --endpoint http://prisma-server:4466
$ prisma deploy
在这里,我们指定了http://prisma-server:4466作为终端点。
prisma-server是在docker-compose.yml中指定的Prisma服务器的服务名称。在Docker Compose中,您可以使用服务名称在服务之间进行通信。换句话说,我们在这里指定了”Prisma服务器的4466端口”作为终端点。
prisma deploy将根据datamodel.prisma执行数据库迁移。这个写法似乎遵循GraphQL的规范,所以请参考GraphQL的相关文档。
当初始化完成后,让我们检查数据结构。请通过浏览器访问localhost:4466/_admin,以确认按照datamodel.prisma所定义的数据结构进行创建。如果能够成功创建,就表示一切正常。

通过这个页面可以进行数据库操作。好像叫Prisma Admin。
试着注册一些数据吧。点击右中间附近的加号,输入值到屏幕右侧的选项卡中。最后点击屏幕右下方的保存按钮即可完成。
让我们最后为 Golang 生成 Prisma Client,然后就结束吧。在 prisma.yml 文件中添加生成 Golang 用 Prisma Client 的配置,并执行生成命令。
endpoint: http://prisma-server:4466
datamodel: datamodel.prisma
generate:
- generator: go-client
output: ./generated/prisma-client/
$ prisma generate
如果一切顺利,文件应该在您指定的输出目录生成。
API服务器
那么,让我们使用生成的Prisma Client来创建API服务器。
您可以像之前一样使用Shell登录API服务器,但我建议您使用VSCode插件Remote-Containers。
只要可以使用Shell即可。
首先,让我们尝试使用刚刚生成的Prisma Client获取数据。我们将参考官方网站的这一部分和这一部分。
$ cd /go/src/app
$ dep init
$ touch main.go
package main
import (
"app/generated/prisma-client"
"context"
"fmt"
)
func main() {
client := prisma.New(nil)
ctx := context.TODO()
users, err := client.Users(nil).Exec(ctx)
if err != nil {
panic(err)
}
fmt.Println(users)
}
没问题,由于正在学习Golang,所以请体谅质量。
暂时先试着运行一下吧。
$ go run main.go
[{ck3ez5b7e00110766n4zr6wro Alice} {ck3ez5b8u001507666qcbs2qy Bob} {ck3ez5b9b001907668hf3pgyw Charles}]
我可以检索到已在数据库中注册的“Alice”、“Bob”和“Charles”的信息,ck3e~是自动生成的ID字符串。
剩下的就是以Json格式对该HTTP请求进行响应了。让我们根据这篇文章和这篇文章继续进行。
package main
import (
"app/generated/prisma-client"
"context"
"log"
"net/http"
"reflect"
"github.com/ant0ine/go-json-rest/rest"
)
var ctx = context.TODO()
var client = prisma.New(nil)
func main() {
api := rest.NewApi()
api.Use(rest.DefaultDevStack...)
router, err := rest.MakeRouter(
rest.Get("/users", GetUsers),
)
if err != nil {
log.Fatal(err)
panic("Failed to setup router.")
}
api.SetApp(router)
log.Fatal(http.ListenAndServe(":8080", api.MakeHandler()))
}
func GetUsers(w rest.ResponseWriter, r *rest.Request) {
users, err := client.Users(nil).Exec(ctx)
if err != nil {
handleError(w, err)
return
}
usersMap := usersToMap(users)
w.WriteJson(usersMap)
}
func handleError(w rest.ResponseWriter, err error) {
log.Fatal(err)
result := map[string]string{"error": "server error"}
w.WriteJson(result)
w.WriteHeader(http.StatusInternalServerError)
}
func usersToMap(users []prisma.User) map[string]map[string]string {
result := make(map[string]map[string]string)
for _, user := range users {
tag := reflect.TypeOf(user).Field(1).Tag.Get("json")
result[user.ID] = map[string]string{tag: user.Name}
}
return result
}
出来上がったら、我们执行并尝试访问。访问的目标是localhost:8080/users。
$ go run ./main.go
{
"ck3ez5b7e00110766n4zr6wro": {
"name": "Alice"
},
"ck3ez5b8u001507666qcbs2qy": {
"name": "Bob"
},
"ck3ez5b9b001907668hf3pgyw": {
"name": "Charles"
}
}
如果可以获取到这样的Json响应,就可以了!
最后
所以,我们可以在虚拟环境中构建以Prisma服务器为核心的开发环境。如果进一步发展,很快就可以实现一个简单的API服务器。但是,我并没有详细介绍GraphQL的细节和Prisma Client的使用方法,为了正常运行,我还需要更多的学习。需要记住的东西会不断增加。
这次我们使用了原始版的Prisma,但目前正在开发计划中的Prisma2即将发布。
由于还不支持Golang(截至2019/11/30),所以我们这次没有使用,但希望尽快能够在Golang中使用。
请参考相关资料。
请参照相关资料。
普瑞斯瑪(Prisma)相關
Prisma – 最快的GraphQL服务器实现
Prisma
Prisma文档
Prisma官方服务器镜像
Prisma2
Docker 相關
终于应该停止使用 docker-compose 中的 links,并使用网络来解决容器之间的名称解析问题,这是 Dockerfile 的最佳实践,以及 Compose 文件的参考资料。
Go相关
据说Go有一个标准的目录结构。
在VSCode中配置Go的模块设置。
尝试使用golang编写REST API ①。
Go-Json-Rest。
标准的Go项目布局。
向Go的结构体添加标签的基本元信息。
Golang。
dep(Golang的依赖管理工具)。
其他
远程容器
图战舰
绘图工具.io