6 23
用Docker定制Golang+Gin+Mongodb+Nginx的开发环境

本文是我日常搭建Docker开发环境的很常用的方式,通过docker搭建一个web的开发环境,能让我们直观了解Docker的工作方式。 本文的例子,为了方便演示,我都是搭建在同一台主机上的,但日常生产环境中比较多的情况是跨主机跨容器交互,我们需要 用到代理镜像的手段解决跨宿主机的通讯, 具体可以参考 官方的 ambassador 配置方式。

在搭建之前,我们先设置一些目录存放我们的Dockerfile, 约定参考如下:

$ mkdir -p /data/apps/mytest/mongodb/

$ mkdir -p /data/apps/mytest/go/

$ mkdir -p /data/apps/mytest/nginx/

我们搭建的服务器ip假设为192.168.139.140,下文都以这个地址作为我们服务器地址

下面的镜像默认以ubuntu作为根镜像

构建MongoDB镜像

MongoDB是一款流行的开放源码的非关系型数据库系统(NoSQL),常用于大数据量、高并 发、弱事务的互联网应用。MongoDB的官网地址是http://www.mongodb.com/ 将MongoDB数据 库系统容器化可以带来以下几个好处。

  • 更容易维护。

  • 启动速度快。

  • 方便与他人进行分享。

编写Dockerfile

进入 /data/apps/mytest/mongodb/

创建我们的Dockerfile文件,内容如下:

FROM ubuntu:14.04
MAINTAINER lihaoquan quanix@163.com
RUN apt-key adv --keyserver hkp://keyserver.ubuntu.com:80 --recv 7F0CEB10
RUN echo "deb http://repo.mongodb.org/apt/ubuntu "$(lsb_release -sc)"/mongodb-org/3.0 multiverse" | tee /etc/apt/sources.list.d/mongodb-org-3.0.list
RUN apt-get update && apt-get install -y --force-yes mongodb-org
RUN apt-get update && apt-get install -y --force-yes mongodb-org=3.0.1 mongodb-org-server=3.0.1 mongodb-org-shell=3.0.1 mongodb-org-mongos=3.0.1 mongodb-org-tools=3.0.1
RUN mkdir -p /data/db
EXPOSE 27017
ENTRYPOINT ["/usr/bin/mongod"]

构建镜像

有了Dockerfile之后,进入Dockerfile文件所在的目录,然后使用build命令来构建镜像:

具体命令参考如下:

sudo docker build --tag lihaoquan/mongodb3 .

构建容器

镜像都建立成功后,我们可以基于镜像构建我们的容器:

sudo docker run -p 27017:27017 --name mongodb_instance -d lihaoquan/mongodb3

这时,我们可以运行 sudo docker ps -a 看我们的容器是否运行起来了。

我们就测试下mongodb的服务是否ok:

我们找一个安装有mongo客户端,然后尝试连接下我们的服务

mongo -port 21017 --host:192.168.139.140

如果顺利连接上,证明我们我们mongodb容器服务已经正常对外提供服务了。

接下来我们可以动手编写一个简单的go服务端并连接我们的mongodb服务,为用户提供查询服务。

构建golang镜像

Gin是基于Go的web开发框架,它具有类似Martini风格的API接口,如果你需要一个高性能的访问速度, 选择它无非是最好的选择。看过Beego、Martini的代码,感觉还是gin符合我的口味。

Gin相关资料:

gin 官网

go http路由框架性能比较

在构建go容器之前,我们先写一个简单的运行例子:

我们进入 /data/apps/mytest/go/

然后创建一个 main.go 的文件,前后敲入以下的内容:

package main

import (
    "fmt"
    "github.com/gin-gonic/gin"
    "gopkg.in/mgo.v2"
    "gopkg.in/mgo.v2/bson"
    "net/http"
)

type Book struct {
    Name string
    Sn   string
}

//测试查询
func TestFindBook(c *gin.Context) {
    sn, _ := c.GetQuery("sn")
    if sn == "" {
        sn = "1"
    }
    session, err := mgo.Dial("mongo_server")
    if err != nil {
        panic(err)
    } else {
        println("连接成功")
    }
    collections := session.DB("test").C("book")
    book := Book{}
    err = collections.Find(bson.M{"sn": sn}).One(&book)
    if err != nil {
    }
    c.String(http.StatusOK, fmt.Sprintf("find book : %s", book.Name))
}

func TestInsertBook(c *gin.Context) {
    sn, _ := c.GetQuery("sn")
    name, _ := c.GetQuery("name")
    res := "no insert"
    if sn != "" && name != "" {
        session, err := mgo.Dial("mongo_server")
        if err != nil {
            panic(err)
        } else {
            println("连接成功")
        }
        collections := session.DB("test").C("book")

        book := &Book{
            Name: name,
            Sn:   sn,
        }
        err = collections.Insert(book)
        if err != nil {
            res = "no insert"
        }
        res = "insert!"
    }
    c.String(http.StatusOK, res)
}

func RegisterRoutes(r *gin.Engine) {
    r.GET("/", func(c *gin.Context) {
        c.String(http.StatusOK, "hello docker !")
    })

    r.GET("/book", func(c *gin.Context) {
        TestFindBook(c)
    })

    r.GET("/insert", func(c *gin.Context) {
        TestInsertBook(c)
    })
}

func main() {
    r := gin.New()
    RegisterRoutes(r)
    r.Run(":8000")
    select {}
}

编写Dockerfile

go服务端程序编写后,在同级目录下创建Dockerfile文件,然后输入以下内容

FROM golang:onbuild
EXPOSE 8000

可以发现,这个Dockerfile非常简单,golang:onbuild为我们提供基础镜像,并进行相关命令封装。

golang:onbuild 会为我们省略了很多的设置步骤,包括ADD、WORKDIR、CMD等设置命令,我们只需要按照规范在项目目录下放置main.go即可。

构建镜像

接着,我们开始创建一个go web应用镜像

sudo docker build -t goapp .

构建容器

最后,基于这个镜像,我们构建我们的容器,并暴露指定的端口和链接到我们的mongodb容器上:

sudo docker run -d --name goapp_api -p 8000:8000 --link mongodb_instance:mongo_server goapp

我们在浏览器上访问 : http://192.168.139.140:8000

index

OK, web服务已经搭建起来了。我们现在可以插入一些数据来测试我们web服务的存储功能:

我们在浏览器输入 : http://192.168.139.140:8000/insert?name=golang in action&sn=2

如果页面输出 insert!则,表示已经成功插入一条数据。

我们再通过浏览器访问: http://192.168.139.140:8000/book?sn=2

若如下图所示, 则我们已经成功通过docker部署了一个gin+mongodb的容器服务。

index

有了基本的web应用服务后,我们要着手为它配置负载,反向代理等功能,毕竟这是互联网生产环境的标配,所以下面我们 增加nginx的支持,继续扩展一下我们的架构吧。

构建Nginx 镜像

Nginx是一款支持HTTP、HTTPS、SMTP、POP3、IMAP等协议的反向代理服务器,也常用 作负载均衡、HTTP缓存和Web服务器。由于它开源、配置简单以及拥有高并发、高性能、低内 存、稳定性高等诸多优良特性,目前已经成为互联网上应用最广泛的Web服务器之一。 本案例以Nginx作为前端服务器,主要提供两方面的功能:

  • 提供静态页面的访问服务;

  • goapp_api反向代理服务。

创建自定义配置文件

进入 /data/apps/mytest/nginx/

创建nginx.conf,内容如下:

worker_processes 4;

events { worker_connections 1024; }

http {

        upstream go-app {
              server 192.168.139.140:8000;
        }
         
        server {
              listen 80;
         
              location / {
                proxy_pass http://go-app;
                proxy_http_version 1.1;
                proxy_set_header Upgrade $http_upgrade;
                proxy_set_header Connection 'upgrade';
                proxy_set_header Host $host;
                proxy_cache_bypass $http_upgrade;
              }
        }
}

我们准备使用这个配置文件来取代nginx的默认配置文件,这需要我们的Dockerfile进行相关配置。

编写Dockerfile

同级目录下,创建Dockerfile

FROM nginx
MAINTAINER lihaoquan quanix@163.com
COPY nginx.conf /etc/nginx/nginx.conf

上面的Dockerfile,我们把自定义的nginx.conf拷贝到/etc/nginx/nginx.conf

这样ngix就会把我们的配置文件作为默认配置文件。

构建镜像

sudo docker build -t lihaoquan/nginx .

构建容器

sudo docker run -d --name nginx_web -p 80:80 lihaoquan/nginx

上面的例子,我们在nginx.conf设置了具体的ip地址192.168.139.140, 如果希望使用别名,而不是具体IP配置, 可以先设置别名goapp_api ,然后构建命令需要进行容器连接 :

$ sudo docker run -d --name nginx_web -p 80:80 --link goapp_api:goapp_api lihaoquan/nginx

我们将容器内的80端口直接映射到外网

验证web应用

我们在浏览器输入:http://192.168.139.140/book?sn=2 来看我们的查询服务是否已经通过nginx代理:

如果能展示下图的输出:

index

证明,我们的nginx的代理服务已经生效了。

总结

使用同样的方法,我们也可以配置 docker + nodejs + mongodb + nginx的配置,具体的方法,大家可以动手试试。