go微服务微服务架构和实践Go语言

go微服务系列之四

2017-11-18  本文已影响182人  Java面试官

这是go微服务系列的第四篇,主要记录的是一些工具的使用和脚本的操作,笑纳~

一、采用gvt管理依赖

​ 同java的maven方案一样,go也具备有管理依赖的方案,如godep、gv、gvt、govendor等,在这里我使用的是gvt,在这里说说我是如何使用gvt实现依赖管理的。由于我自己平常都是使用ubuntu做开发和日常使用,这里就只说如何在ubuntu上操作,windows的额我就不说了~

1.1 安装gvt

首先安装gvt(这里请自行翻墙)

go get -u github.com/FiloSottile/gvt
1.2 使用gvt

进入项目src下,使用以下命令:

$ gvt fetch github.com/BurntSushi/toml

​ 之后在src下面就会看到生成文件夹vendor以及vendor下面生成相应依赖和manifest,之后再多次重复gvt fetch xxx命令即可生成完整依赖(xxx修改为相应的依赖),图示如下:

image.png

​ 当采用了gvt管理依赖后,启动项目的时候系统会默认从src/vendor下面寻找相应的依赖。

二、采用docker做容器部署项目

​ 为了比较完整的玩这一套微服务项目,我引入了docker做容器,并在docker上跑这个服务,这里说说我是如何采用docker做容器的。

2.1 安装docker

具体如何安装docker可以查看官网(https://docs.docker.com/engine/installation/linux/docker-ce/ubuntu/),这里我就不提了,安装成功后,在命令行输入:docker version 有输出版本等信息即意味着安装成功。

2.2 使用Dockerfile构建镜像

​ 我先在项目根目录创建了dockerbase,在里边放置我的Dockefile文件,Dockerfile内容如下,具体的可以查看源码:

FROM ubuntu:14.04

MAINTAINER ricoder "ricoder142@gmail.com"

ADD http://mirrors.163.com/.help/sources.list.trusty /etc/apt/sources.list

COPY conf/redis.conf /etc/redis/6379.conf
COPY conf/consul.json /etc/consul/consul.json
COPY supervisor/*.conf /etc/supervisor/conf.d/

RUN apt-get update && \
    apt-get -y install build-essential && \
    apt-get -y install openssh-server && \
    apt-get -y install libssl-dev && \
    apt-get -y install git && \
    apt-get -y install vim && \
    apt-get -y install wget && \
    apt-get -y install curl && \
    apt-get -y install unzip

RUN apt-get -y install supervisor && \
    apt-get -y install redis-server && \
    apt-get -y install mysql-server && \
    apt-get -y install mysql-client && \
    mkdir -p /data/services/consul-0.9/bin/ && \
    wget https://releases.hashicorp.com/consul/0.9.0/consul_0.9.0_linux_amd64.zip && \
    unzip consul_0.9.0_linux_amd64.zip && \
    mv ./consul /usr/local/bin/ && \
    mkdir /data/consul/ && \
    mkdir -p /data/logs/gologs/ && \
    mysql_install_db && \
    update-rc.d -f mysql defaults && \
    wget https://storage.googleapis.com/golang/go1.9.1.linux-amd64.tar.gz && \
    tar zxf go1.9.1.linux-amd64.tar.gz && \
    mkdir -p /data/goapp && \
    mv go/ /data/services/ && \
    rm -rf consul_0.9.0_linux_amd64.zip go1.9.1.linux-amd64.tar.gz && \
    echo "export GOROOT=/data/services/go\nPATH=$PATH:/data/services/go/bin" >> ~/.bashrc

EXPOSE 3306 8500 6379 8082 8083 8084 8085 5324 9999

CMD chown -R mysql:mysql /var/lib/mysql && \
    service mysql start && \
    supervisord -c /etc/supervisor/supervisord.conf -n

​ 构建的镜像主要实现的功能是:

​ 在ubuntu14.04系统下搭建go生产环境,安装git、vim等工具,安装supervisor管理后台进程,安装redis和mysql,安装consul实现服务发现,暴露部分端口,启动mysql和supervisord等。

Dockerfile涉及的命令有:

(1)FROM(指定基础镜像)

​ 该指令必须指定且需要在Dockerfile其他指令的前面。后续的指令都依赖于该指令指定的image。FROM指令指定的基础image可以是官方远程仓库中的,也可以位于本地仓库。
​ 该指令有两种格式:

        b.FROM <image>

​ 指定基础image为该image的最后修改的版本。或者:

        a.FROM <image>:<tag>  

​ 指定基础镜像为该镜像的一个tag版本。

​ 可以通过我写的Dockerfile看出我指定的基础镜像是14.04 的。

(2)MAINTAINER(用来指定镜像创建者信息)

​ 该指令用于将image的制作者相关的信息写入到image中。当我们对该image执行docker inspect命令时,输出中有相应的字段记录该信息。
​ 指令格式:

        MAINTAINER <name>  

​ 可以在我写的Dockerfile中看出镜像创建者的信息是:ricoder "ricoder142@gmail.com"

(3)ADD(从src复制文件到容器的dest路径)

​ 该指令将所有拷贝到container中的文件和文件夹权限为0755,uid和gid为0;如果是一个目录,那么会将该目录下的所有文件添加到container中,不包括目录;如果文件是可识别的压缩格式,则docker会帮忙解压缩(注意压缩格式);如果<src>是文件且<dest>中不使用斜杠结束,则会将<dest>视为文件,<src>的内容会写入<dest>;如果<src>是文件且<dest>中使用斜杠结束,则会<src>文件拷贝到<dest>目录下。
​ 指令格式:

        ADD <src> <dest>  

​ <src> 是相对被构建的源目录的相对路径,可以是文件或目录的路径,也可以是一个远程的文件url;<dest> 是container中的绝对路径

​ 可以在Dockerfile中看出我主要是将conf下和supervisor下的文件复制容器内,复制conf的目的是修改配置,而复制supervisor的目的我会在第三章节说到。

(4)COPY
​ COPY的语法与功能与ADD基本相同,不同的是不支持上面讲到的<src>是远程URL、自动解压这两个特性,所以上面我并没有使用COPY,而是使用了ADD,不过官方建议尽量使用COPY,这是因为虽然COPY只支持本地文件拷贝到container,但它的处理比ADD更加透明,官方建议只在复制tar文件时使用ADD(因为ADD会自动解压文件),如ADD trusty-core-amd64.tar.gz 。

​ 可以在我写的Dockerfile中看出,我是将conf和supervisor文件夹下的文件拷贝到指定的路径,conf下的是对redis和consul的设置,而supervisor的主要实现的是后台进程的管理,等等我会在第三部分做个详细的讲解,此处先略过。

(5)RUN
​ RUN指令会在当前镜像的顶层执行任何命令,并commit成新的(中间)镜像。
​ 指令格式:

        RUN <commnad>或RUN ["executable", "param1", "param2"]

​ 第一种格式是shell格式,相当于执行/bin/sh -c "<command>",例如我Dockerfile中的例子:

        RUN apt-get -y install supervisor

​ exec格式,不会触发shell,所以$HOME这样的环境变量无法使用,但它可以在没有bash的镜像中执行,而且可以避免错误的解析命令字符串:

        RUN ["apt-get", "install", "supervisor", "-y"]或RUN ["/bin/bash", "-c", "apt-get install -y supervisor"]

(6)EXPOSE
​ EXPOSE指令会告诉容器在运行时要监听的端口,不过这个端口是用于多个容器之间通信用的,外面的host是访问不到的。而要把端口暴露给外面的主机,在启动容器时使用-p
选项,这一点在后面将会有提及。示例:

    EXPOSE 3306 8500 6379 8082 8083 8084 8085 5324 9999

(7)CMD
​ 一个Dockerfile里只能有一个CMD,如果有多个,只有最后一个生效。CMD指令的主要功能是在build完成后,为了给docker run启动到容器时提供默认命令或参数,这些默认值可以包含可执行的命令,也可以只是参数(此时可执行命令就必须提前在ENTRYPOINT中指定)。
​ CMD与RUN的区别在于,RUN是在build成镜像时就运行的,而CMD指令实在build完成后运行的,所以RUN先于CMD运行,其次CMD会在每次启动容器的时候运行,而RUN只在创建镜像时执行一次。
​ 可以从我的Dockerfile中看出在这里CMD的作用是启动mysql和supervisord。

2.3 构建镜像

使用命令:

docker build -t gomicro-env .

可以在命令行中看到输出:

ricoder# docker build -t gomicro-env .Sending build context to Docker daemon  42.5 kBStep 1/10 : FROM ubuntu:14.04 ---> dea1945146b9Step 2/10 : MAINTAINER ricoder "ricoder142@gmail.com" ---> Running in d4da66553673 ---> 2e8b5ccd3c9e .......

构建成功后,在命令行输入:

ricoder# docker images

可以在列表中看到:

gomicro-env           latest             9c9883edc1db        20 hours ago         899 MB
2.4 启动容器

使用命令:

 docker run --name=$Container -p 18087:8082 -p 18505:8500 -d -v `pwd`:/data/deploy/$ProjectName gomicro-env

查看容器:

ricoder# docker container ls

可以在命令行中看到容器的详细信息。
​ 这里大概讲解下docker run这一行话的意思,--name是容器名的参数,-p 对应着的是本地端口映射到容器端口,这里的-p 18087:8082意味着本地的18087映射到8082端口,这样在本地访问18087端口的时候可以访问到容器的8082端口,-d意思是后台运行容器,并返回容器ID,-v参数的给容器添加一个数据卷,即将本地的项目挂载到容器中。

2.5 在容器中创建数据库&跑起服务

​ 我在dockerbase目录下面新加了一个init.sh文件,内容如下:

!/bin/bash
mysql -u root -e "CREATE DATABASE gomicro "
R=/data/deploy/gomicro
cd $Rbash 
build_local.sh all

​ 然后运行如下命令:

docker exec $Container bash /data/deploy/$ProjectName/dockerbase/init.sh

​ 该命令的功能是在容器$Container中跑起这个init.sh脚本,实现的功能是创建数据库gomicro和跑起build_local.sh脚本并且携带参数all,接下来看看build_local.sh脚本

#!/bin/sh


if [ $1 == "all" ]; then
    for srv in `ls src`; do
        if [ ${srv:0-4} == "-srv" ]; then
            echo "开始更新$srv"
            GOROOT=/data/services/go GOBIN=/data/goapp/wolf/bin GOPATH=`pwd`:`pwd`/vendor /data/services/go/bin/go install $srv && sudo supervisorctl restart wolf-$srv:*
        fi
    done
else
    for srv in "$@"
    do
        if [ "${srv:0-4}" != "-srv" ]; then
            srv="${srv}-srv"
        fi
        echo "开始更新$srv"
        GOROOT=/data/services/go GOBIN=/data/goapp/wolf/bin GOPATH=`pwd`:`pwd`/vendor /data/services/go/bin/go install $srv && sudo supervisorctl restart wolf-$srv:*
    done
fi

​ 从脚本中可以看出,当携带的参数是all的时候实现的功能是 install go服务和使用supervisorctl重启指定的后台进程,至于supervisor如何管理后台进程我会在第三章节说到。

三、采用supervisor管理后台进程

3.1 什么是supervisor

​ Supervisor是一个 Python 开发的 client/server 系统,是一款Linux下的进程管理软件,可以管理和监控类 UNIX 操作系统上面的进程。它可以同时启动,关闭多个进程,使用起来特别的方便,最主要的两个功能是:

3.2 在容器内安装supervisor

​ 由于我是在docker容器内部署项目,所以supervisor也是在容器内安装和使用,不过本地也是一样的。可以在我写的dockerfile中看到:

    RUN apt-get -y install supervisor && \

​ 我在容器中安装了supervisor,然后在dockerfile中采用以下命令启动supervisor:

    supervisord -c /etc/supervisor/supervisord.conf -n

​ 我们可以先使用以下命令登录docker :

    docker exec -it $Container /bin/bash

​ 登录成功后采用一下命令查看supervisor是否启动成功:

    ps -ef | grep supervisor | grep -v grep
    root       448     1  0 15:04 ?        00:00:00 /usr/bin/python /usr/bin/supervisord -c /etc/supervisor/supervisord.conf -n

​ 证明启动成功。

3.3 在容器内使用supervisor管理后台进程

​ 首先,我在Dockerfile中做了如下操作:

    COPY supervisor/*.conf /etc/supervisor/conf.d/

​ 将以下的文件全都复制到容器的/etc/supervisor/conf.d/文件夹下面

image.png

​ 以api-srv.conf为例,目的是将api-srv微服务进程交给supervisor管理,源码如下:

    [program:class-api-srv]
    command=/data/goapp/gomicro/bin/api-srv
    process_name=class-user-srv
    autorestart=true
    redirect_stderr=true
    stderr_logfile=/data/logs/api-srv.err.log
    stdout_logfile=/data/logs/api-srv.out.log
    user=root

​ command 启动命令

​ process_name 进程的名字,这里和program一致

​ autorestart=true 程序异常退出后自动重启

​ stderr_logfile stderr 日志输出位置

​ stdout_logfile stdout 日志输出位置

重新启动supervisor

    supervisord -c /etc/supervisor/supervisord.conf -n

使用以下命令查看已经在跑的并且被supervisor管理的进程:

    supervisordctl status

结果如下:

root@133f583a598b:/# supervisorctl status
api-srv                          RUNNING    pid 544, uptime 0:00:12
consul-server                    RUNNING    pid 543, uptime 0:00:12
redis-6379                       RUNNING    pid 545, uptime 0:00:12

可以看出目前被supervisor管理的进程有三个。

3.4 使用supervisor添加管理进程

为要管理的进程按照3.3中写到的那样,添加一份conf文件,并放在supervisor目录下面,之后在docker容器内运行命令:

    supervisorctl reload

即可管理新增进程。
四、采用脚本进行自动化部署
为了开发方便,我采用了shell脚本部署项目、操作docker、操作数据库等,具体可以查看ctrl.sh文件、build_local.sh文件、build_proto.sh文件和init.sh文件。

Last、系列总结

这是go微服务系列的第四篇,接下来我会将该项目真正用到项目中,开发电影票在线购票系统(毕设),具体可以关注项目:
https://github.com/wiatingpub/MTBSystem ,不介意的话也可以给个star哈。
tip:该项目的源码(包含数据库的增删查改的demo)可以查看 源代码

有兴趣的可以关注我的个人公众号 ~

qrcode_for_gh_04e57fbebd02_258.jpg
上一篇下一篇

猜你喜欢

热点阅读