作者 青鸟
在试过了systemed部署服务之后,尝试了一下docker来部署,相较于systemed的部署,docker更加优雅和方便,但在这个过程中也是遇到了大大小小的问题,也是做了很多优化,特地记录一下,值得注意的是我没有使用docker-compose来部署,而是单纯的容器间通讯,之后会再写一篇来记录。文章较长,有错误的欢迎指出
关于docker环境的安装,按照官方教程即可以轻松解决,同时需要注意Docker Hub被墙了,因此要用镜像源,推荐使用腾讯云的镜像仓库
搭建生产环境#
这里的生产环境主要指的就是redis和mysql这两个数据库,这里有一个大坑就是当你卸载容器的时候,数据库里的数据会随之销毁,这显然是不符合我们的要求的,解决办法就是配置的时候使用挂载数据卷的方式,将数据库信息挂在到宿主主机上,以此可以在销毁或者重启容器的时候做到数据持久化。
mysql配置#
我们首先创建三个文件夹
1
2
3
4
5
6
| #配置文件
mkdir /usr/local/mysql/conf
#数据存储
mkdir /usr/local/mysql/data
#mysql日志
mkdir /usr/local/mysql/logs
|
首先编辑配置文件
创建一个my.cnf
1
2
3
4
5
6
7
8
9
10
11
12
13
14
| [mysqld]
pid-file = /var/run/mysqld/mysqld.pid
socket = /var/run/mysqld/mysqld.sock
datadir = /var/lib/mysql
secure-file-priv= NULL
# Disabling symbolic-links is recommended to prevent assorted security risks
symbolic-links=0
character-set-server=utf8
[client]
default-character-set=utf8
[mysql]
default-character-set=utf8
# Custom config should go here
!includedir /etc/mysql/conf.d/
|
配置文件之所以不采用容器内部的,是因为可能存在中文编码的问题,稳妥起见还是自己写一个配置让人放心
接下来,我们直接把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
2
3
4
5
6
| #配置文件
mkdir /usr/local/mysql/conf
#数据存储
mkdir /usr/local/mysql/data
#mysql日志
mkdir /usr/local/mysql/log
|
我们从网上找一份redis.conf配置,复制下来即可
这里要注意几个很坑的点
1
2
3
4
5
6
| 1、允许redis外地连接,这里的本地并不是宿主计算机的本地,docker使用了Linux的Namespaces技术来进行资源隔离,其中就包括了网络环境,一个Network Namespace提供了一份独立的网络环境,包括网卡、路由、Iptable规则等都与其他的Network Namespace隔离。
注释掉 # bind 127.0.0.1
2、修改daemonize 这个是个很坑的点,就是daemonize是代表开启守护进程模式,这和docker的-d是冲突的,会导致容器启动失败
daemonize no
3、开启redis数据持久化
appendonly yes
|
然后在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
2
3
4
5
6
| FROM scratch
MAINTAINER cbluebird
WORKDIR /app
COPY example /app
EXPOSE 6060
CMD ["./example"]
|
然后在bash中执行下面的命令
1
| docker build -t example .
|
然后使用下面的命令查看Image是否存在
查看到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
2
3
4
5
| -v 是数据卷挂载
-p 端口映射,将容器的端口映射到宿主机的端口上,来和外界通讯
--name 容器别名
--privileged 是否使用管理员权限
--restart 是否自动启动,使得容器具有自愈功能,可以开机自动启动
|
最后我们使用
1
| docker logs -f user-center
|
就可以查看容器的日志了,至此一个docker部署的应用就优雅地跑起来了
Docker常用的命令#
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
| # 停止一个容器
docker stop wejh
#运行一个容器
docker start exapmle
#重新运行一个容器
docker restart example
#从本地删除一个容器
docker rm example
#从本地删除一个镜像
docker rmi example
#查看容器的日志
docker logs -f example
#通过一个bash进入一个容器内部
docker exec -it mysql /bin/bash
#查看所有在运行的容器
docker ps
#查看所有容器
docker ps -a
#查看本地所有的镜像
docker images
#打包成镜像
docker build -t example .
# 查看m容器的IPAddress
docker inspect <container_id> | grep IPAddress
#会以 json 格式得到 docker 镜像/容器的元数据
docker inspect example
|
文章较长,有错误的欢迎指出
参考文章:
Docker 网络及通信方式
添加镜像仓库
官方下载教程