Docker部署go项目

首先我们把我们写的go项目通过Xftp传到服务器上面,或者通过git从Coding里面拉取一份 ,未来方便起见我是把我的所有的go项目都放在了/usr/local/goproject目录下面。

阿里云服务器安装git

首先在服务器上面安装git ,阿里云服务器安装git很简单

yum install git #安装git
git version #查看Git的版本

通过Dockerfile文件打包镜像

git安装完成,代码放在服务器上面之后,我们就可以通过代码中的Dockerfile文件构建一个镜像

首先把目录切换到Dockerfile所在的目录下面,直接执行下面的命令

docker build -f Dockerfile -t 镜像名 .

值得一提的是,Dockerfile文件官方推荐的名字是Dockerfile,如果是Dockerfile的话,我们可以省略-f参数 ,另外,后面的 . 是一定不能少的

当看到下方的Successfully 就代表成功构建了一个镜像,有了镜像,我们就可以通过镜像启动容器了,接下来我们详细看一下我们的Dockerfile文件

FROM golang:alpine
# 为我们的镜像设置必要的环境变量
ENV GO111MODULE=on \
    CGO_ENABLED=0 \
    GOOS=linux \
    GOARCH=amd64\
    GOPROXY=https://goproxy.cn
# 设置/usr/local/goproject,进入容器就会直接进入到这个目录下,而不是进入到默认根目录下面
WORKDIR /usr/local/goproject
# 复制项目中的 go.mod 和 go.sum文件并下载依赖信息
COPY go.mod .
COPY go.sum .
RUN go mod tidy
    
# 将代码复制到容器中
COPY . .

通过镜像运行容器

docker run -it -v /usr/local/goproject:/usr/local/goproject -v /etc/localtime:/etc/localtime -p 8080:8080 --cap-add SYS_TIME --name ding_1.0 ding_1.0 /bin/sh 

其中 -v 是挂载,挂载就是把服务器宿主机和容器中的保持一致,我们容器里面有一个项目的代码,服务器宿主机上面也有一份代码,应该保持一致,这样的话,我们改变其中一个地方的代码,另外一个地方的代码也会随之改变。

第一个/usr/local/goproject 是我们服务器宿主机放golang代码的地方,后面第二个/usr/local/goproject 是我们容器中放代码的地方,为了方便起见,我把目录都起得一样。后面的/etc/localtime也是一样,这个是为了让我们的容器的时间和服务器宿主机的时间保持一致。

-p是端口映射,我们的阿里云服务器一定要开放8080端口

-cap-add SYS_TIME 是赋予了容器可以修改时间的权限

这样,我们就启动了一个容器,现在的话,我们直接进入到容器内部

docker exec -it ding1.0 sh #注意我们此处不能使用bash,因为我们使用的基础镜像是golang:alpine

可以看到,我们进入容器的默认位置就在/usr/local/goproject中,这是因为我们设置镜像的时候,我们的workdir就是/usr/local/goproject

我们进入到项目的目录下面,可以看到这就是我们的代码

我们可以看到main.go 文件,我们可以直接编译main.go

go build -o ding main.go# -o 参数可以让我们制定编译成具体的名字,而不是编译成main

当编译完成之后,我们就可以看到我们的目录下面有一个绿色的ding文件,这个文件就是可以直接运行的二进制文件

现在我们来运行这个文件

nohup /usr/local/goproject/ding_server/ding> start.log 2>&1 &
# nohup表示不挂断地运行命令,也就是你即便关掉终端,依然不会终止
# > start.log 将结果输出到start.log中
后面的 2>&1 & 我也不懂,把其他人的解读复制过来
# 2>&1,2是标准错误,1是标准输出,就是把错误结果打印出来,&1是就是对标准输出的引用
# 最后的&是是把该命令以后台的job的形式运行,可以通过jobs -l命令来查看当前的所有job

好了,至此我们的项目就已经部署好了,我们在本地的golang里面写好代码后,推送到Coding上面,经过管理员合并代码之后,我们就可以拉去新的代码了。

还记得吗?我们项目的代码再服务器的/usr/local/goproject下面,我们进到这个目录下面

然后进入项目目录ding-server下面,该目录下面是有一个隐藏的 .git文件,我们可以直接在此处拉取代码

git pull origin develop 

在服务器宿主机上面拉去代码之后,容器里面的代码也是会发生改变的,因为我们当时启动容器的时候进行了挂载,服务器和容器的代码会保持一致。

然后我们进入到容器里面,重新go build -o ding main.go 一下 ,然后kill -9 老进程号 ,然后再 nohup不挂断执行一下,这就是更新项目的流程。

不足与缺陷

但是这样很麻烦,需要我们手动来操作,所以下面的话,我们通过shell命令来编写一个脚本文件,我们可以通过运行这个脚本文件来一键自动化部署。

下面我们就开始编写一下这个脚本文件。

编写脚本文件实现自动化部署

容器里面安装git

在编写脚本文件之前,我们需要在容器里面安装git来拉取代码。

有的同学可能会问,我们已经在服务器宿主机上面安装git拉取码了,服务器宿主机是和容器挂载过的,为什么还要在容器里面安装git呢?

我们确实是在服务器宿主机上面安装了git并且可以拉去代码,但是拉取代码后的杀死老进程,重新编译main.go文件,再重新nohup,是必须在容器里面进行的,所以我们这个时候在容器里面安装git之后,我们统一在容器里面做这一套操作,就实现了自动化部署。

下面是具体的安装git的步骤,我在网上找了相关教程,发现讲的都是奇奇怪怪的gitlab啥的,完全搞不懂安装个git干嘛要搞这玩意。 我想起来以前安装都事直接yum install git ,但是我执行报了错。

去网上找了相关的文档,才发现我们构建镜像的时候,用的镜像不是centos镜像,而是apline镜像,apline是没有yum,而是apk , apk的命令是apk add git

echo -e http://mirrors.ustc.edu.cn/alpine/v3.12/main/ > /etc/apk/repositories #先设置一个镜像
apk update  #直接更新此工具大概率会失败 
apk add git #容器中安装git

至此,容器中的git安装成功。

编写脚本文件

我们在容器中项目录下面新建一个update.sh文件 , 并编写此文件,具体如下

touch update.sh 
vi update.sh #apline镜像中是没有vim的,我们使用vi即可

这是具体的update.sh文件内容

time1=$(date "+%Y-%m-%d-%H:%M") #获取到当前的时间
cp ding ../backup/${time1} #把我们旧的二进制文件给移动到上一层目录的backup文件夹里面进行备份,命名规则就是根据时间time1
git pull origin develop # 去coding上面拉去最新的代码
go build -o ding main.go # 编译新的main.go文件
kill -9 "$(pgrep -f ding)" #杀死之前的老进程
nohup ./ding > start.log 2>&1 & # 开启现在的新进程
echo "OK" #给出成功提示

现在,我们每次在golang文件里面写好代码,提交到coding上面后,直接进入到容器中,执行 sh update.sh命令即可自动化部署了