使用Docker优雅地部署Goland服务
作者 青鸟
在试过了systemed部署服务之后,尝试了一下docker来部署,相较于systemed的部署,docker更加优雅和方便,但在这个过程中也是遇到了大大小小的问题,也是做了很多优化,特地记录一下,值得注意的是我没有使用docker-compose来部署,而是单纯的容器间通讯,之后会再写一篇来记录。文章较长,有错误的欢迎指出
关于docker环境的安装,按照官方教程即可以轻松解决,同时需要注意Docker Hub被墙了,因此要用镜像源,推荐使用腾讯云的镜像仓库
搭建生产环境
这里的生产环境主要指的就是redis和mysql这两个数据库,这里有一个大坑就是当你卸载容器的时候,数据库里的数据会随之销毁,这显然是不符合我们的要求的,解决办法就是配置的时候使用挂载数据卷的方式,将数据库信息挂在到宿主主机上,以此可以在销毁或者重启容器的时候做到数据持久化。
mysql配置
我们首先创建三个文件夹
1 | 配置文件 |
首先编辑配置文件
创建一个my.cnf
1 | [mysqld] |
配置文件之所以不采用容器内部的,是因为可能存在中文编码的问题,稳妥起见还是自己写一个配置让人放心
接下来,我们直接把mysql的Image给pull下来,然后run一下就好了
1 | docker run --restart=always -d -v /usr/local/mysql/conf/my.cnf:/etc/mysql/my.cnf -v /usr/local/mysql/logs:/logs -v /usr/local/mysql/data/mysql:/var/lib/mysql -p 3306:3306 --name mysql -e MYSQL_ROOT_PASSWORD=123456 mysql |
之后就像正常的数据库一样,做一个简单的配置,开一个用户可以对外连接的即可
redis配置
1 | 配置文件 |
我们从网上找一份redis.conf配置,复制下来即可
这里要注意几个很坑的点
1 | 1、允许redis外地连接,这里的本地并不是宿主计算机的本地,docker使用了Linux的Namespaces技术来进行资源隔离,其中就包括了网络环境,一个Network Namespace提供了一份独立的网络环境,包括网卡、路由、Iptable规则等都与其他的Network Namespace隔离。 |
然后在log中新建一个redis.log即可
最后从Hub中pull下redis的Image,run一下即可
1 | docker run --restart=always -d --privileged=true -p 6379:6379 -v /usr/local/docker/redis/conf/redis.conf:/etc/redis/redis.conf -v /usr/local/docker/redis/log/redis.log:/var/log/redis.log -v /usr/local/docker/redis/data:/data --name redis redis redis-server / |
将Goland程序打包成Image
我们先将程序打包成所需的二进制文件,然后用sftp将二进制文件和配置文件一起上传到服务器上的文件下
这里需要说明的是为什么打包二进制,很多网上的文章都是在容器内部打包的,其实我们去查看内存大小会发现容器的磁盘占用是很大的,但是其实最后运行的只有一个二进制文件,同时我们还在镜像中调用了goland镜像,这显然不是我们运行所必需的,因为build会打包成所需的动态连接库,所以go的环境就不需要了。我们直接引入scratch这个空镜像就OK了
打包的时候可以使用一下go命令打包
1 | CGO_ENABLED=0 GOOS=linux GOARCH=amd64 GIN_MODE=release go build -o example |
然后在这个文件夹下创建一个dockerfile
1 | FROM scratch |
然后在bash中执行下面的命令
1 | docker build -t example . |
然后使用下面的命令查看Image是否存在
1 | docker images |
查看到example已经在Image已经在本地了,之后运行即可
运行Image
yaml的配置
首先我们要注意的是在yaml配置中mysql和redis的配置,我们不能简单的理解出来为本地环境localhost,与之前redis中提到的一样,docker使用了Linux的Namespaces技术来进行资源隔离,其中就包括了网络环境,一个Network Namespace提供了一份独立的网络环境,包括网卡、路由、Iptable规则等都与其他的Network Namespace隔离。
这里主要有四种解决办法
第一种也就是最直接的,直接替换掉本地的localhost,换成docker分配的IPAddress即可,我们使用下面命令即可查看容器的IPAddress
1 | docker inspect <container_id> | grep IPAddress |
第二种办法是在运行时使用--link
来连接,比如--link mysql:mysql
就可以在这个容器里使用mysql的本地了
第三种方法是使用host,这样子就和宿主机处于同一个网络下了,容器将不会虚拟出自己的网卡,配置自己的IP等,而是使用宿主机的IP和端口。但是这种方法显然丧失了使用docker很重要的原因,容器的隔离性和安全
第四种方法是自定义网络,将几个容器都放在一个虚拟网络环境下,这就比较麻烦了,感兴趣的可以自己google
挂载yaml
其实我们也可以将yaml打包进docker中,但是这样子将不利于我们配置的更改,因为我们一般的查看和更改文件都是需要进入到容器中,我们一般使用下面命令进入
1 | docker exec -it mysql /bin/bash |
但是这里就存在了一个问题就是我们拿什么去修改呢,我们在打包的时候其实并没有将编辑器打包进去,这就导致了修改的难度很大,于是一个比较优雅的方式就是使用数据卷挂载,这样子就可以将配置文件存放在宿主机中来维护,我们在run的时候使用-v
即可
运行容器
说完了上述两个坑,我们就可以直接运行了
1 | run --privileged=true -p 6060:6060 -v /opt/example/config.yaml:/app/config.yaml --name example example |
其中的几个配置需要说明一下
1 | -v 是数据卷挂载 |
最后我们使用
1 | docker logs -f user-center |
就可以查看容器的日志了,至此一个docker部署的应用就优雅地跑起来了
Docker常用的命令
1 | 停止一个容器 |
文章较长,有错误的欢迎指出
参考文章:
Docker 网络及通信方式