五分钟用Docker快速搭建Go开发环境

挺早以前在我写过一篇用 `Docker`搭建LNMP开发环境的文章:[用Docker搭建Laravel开发环境](?__biz=MzUzNTY5MzU2MA==&mid=2247483807&idx=1&sn=061f9a4f6711d7c4550c4f9012d9ad4e&chksm=fa80d008cdf7591edd2373aae91c76b4b13ec8a30a6f55d4f851556a288ca4c25f428910ddd3&scene=21#wechat_redirect),里面详细介绍了将 `nginx`、 `mysql`和 `php`三个容器用 `docker-compose`编排成 `LNMP`开发环境的步骤,今天来说说怎么用 `Docker`快速搭建 `Go`语言项目的开发环境。

因为靠`Go`本身自带的标准库就能实现高性能的 `HTTP`服务器,不熟悉的同学买它,呃说错了,看它:[深入学习用Go编写HTTP服务器](?__biz=MzUzNTY5MzU2MA==&mid=2247484112&idx=1&sn=79d0d3167d0d962fe41ec00cdafffbb0&chksm=fa80d347cdf75a51183182f14622af766538ca0c5335012e5e1cc50b100e78f2954fa3943770&scene=21#wechat_redirect)。所以用 `Docker` 构建 `Go`的开发环境比构建 LNMP 开发环境要简单很多,如果没有太多定制化要求甚至都不用写 `Dockerfile`自己构建镜像,直接使用官方的 `golang`镜像即可。

### 获取Docker镜像

我们使用官方最新稳定版的镜像 `golang:latest`, 获取镜像前先得确保你电脑上运行了 `Docker` 客户端,没有的去官网下载一下吧这里就不多说了。

下载`dockerHub`上的镜像直接使用命令:

```shell
docker pull golang
```

下载完镜像后用镜像运行一个容器:

```shell
docker run --rm -it --name go-http-demo golang bash
```

上面这个命令用镜像 `golang`创建了一个名为 `go-http-demo`的容器,在容器中创建了一个 `Bash`会话。`--rm`选项指定容器退出后自动移除容器。

运行完上面的命令后我们就进入了运行的容器中,运行 `go version` 查看以下 `go`的版本:

```
root@965425c5bdcf:/go# go version
go version go1.13.6 linux/amd64
root@965425c5bdcf:/go#
```

你可以根据自己的需要在`https://hub.docker.com/_/golang` 中查找自己需要的版本的 `golang`镜像运行容器。

### 在容器中运行Go项目

我们使用《[深入学习用Go编写HTTP服务器](?__biz=MzUzNTY5MzU2MA==&mid=2247484112&idx=1&sn=79d0d3167d0d962fe41ec00cdafffbb0&chksm=fa80d347cdf75a51183182f14622af766538ca0c5335012e5e1cc50b100e78f2954fa3943770&scene=21#wechat_redirect)》中最后写的支持优雅关停服务的 `HTTPServer`的源码,将它放到 `Docker`容器里伺服宿主机的请求。`HTTP Server`的源码如下,想探究代码具体怎么实现的看链接里的文章就好了。

```go
package main

import (
"context"
"fmt"
"log"
"net/http"
"os"
"os/signal"
"syscall"
)

func main() {
mux := http.NewServeMux()
mux.Handle("http://www.likecs.com/", &helloHandler{})

server := &http.Server{
Addr: ":8080",
Handler: mux,
}

// 创建系统信号接收器
done := make(chan os.Signal)
signal.Notify(done, os.Interrupt, syscall.SIGINT, syscall.SIGTERM)
go func() {
<-done

if err := server.Shutdown(context.Background()); err != nil {
log.Fatal("Shutdown server:", err)
}
}()

log.Println("Starting HTTP server...")
err := server.ListenAndServe()
if err != nil {
if err == http.ErrServerClosed {
log.Print("Server closed under request")
} else {
log.Fatal("Server closed unexpected")
}
}
}

type helloHandler struct{}

func (*helloHandler) ServeHTTP(w http.ResponseWriter, r *http.Request) {
fmt.Fprintf(w, "Hello World")
}
```

把源码放在本地电脑的 `/Code/go/src/example.com/http-demo/main.go`中,文件目录你们做的时候根据自己的情况写路径。

接下来就要把这个代码放到容器里去运行了,切到代码目录里执行如下命令:

```
docker run --rm -it --name go-http-demo \
-v $PWD:/go/src/example.com/go-http-demo \
-p 8000:8080
golang
```

`-v`选项允许我们挂载多个本地目录或者数据卷到容器中,更改会在容器内外相互同步,上面的命令将 `/Code/go/src/example.com/go-http-demo/`挂载到了容器的 `/go/src/example.com/go-http-demo`。

`-p`指定主机和容器的端口映射,因为代码里 `HTTP`服务是监听 `8080`端口的,所以我们将主机的 `8000`端口和容器的 `8080`端口做了映射。

执行完上面的命令,我们切换到到容器里的 `Bash`会话,切到代码目录运行 `go run main.go`后,在自己的电脑上打开浏览器访问 `http:localhost:8080`看到下图中的页面就证明服务器在容器里已经正常运行起来了。

![](https://user-gold-cdn.xitu.io/2020/1/30/16ff47b8a056fb09?w=1000&h=750&f=png&s=13544)

### 用 docker-compose 管理容器

通过上面的内容我们已经用 `Docker`构建好了一个 `Go`的开发环境,不过每次打那堆命令,还要进容器执行 `go`命令启动程序太费事了,我们用 `docker-compose`把上面那些流程自动化一下。

在项目代码根目录创建`docker-compose.yml`:

内容版权声明:除非注明,否则皆为本站原创文章。

转载注明出处:https://www.heiqu.com/zwgxwx.html