我尝试在Golang中使用Docker启动web服务器
我最近想使用golang来进行并行批处理。而且我想要并行处理大量数据,所以我想使用可以轻松增加资源的docker。
如果只是在docker上启动和开发golang,那么并不是太困难。但是,当我想要在docker上启动守护进程时,就必须熟练掌握docker命令,所以我打算在docker的圣诞节日历上悄悄地发布一下。
1. 准备包含golang的Docker。
有一个由社区管理的 Docker 镜像,我要拿来用。
$ docker pull golang
为了在Docker内进行开发,安装vim。
$ docker run -it golang
(dockerコンテナ内)
# apt-get update && apt-get upgrade
# apt-get vim
c. 提交并推送 Docker
$ docker commit [container ID] [dockerhub username]/golang
$ docker push [container ID]
d. 从新创建的映像中再次启动容器
$ docker run -it [dockerhub username]/golang
用Go语言编写服务器脚本。
当运行 docker run -it 进入 docker 时,我认为会进入 root 用户的 /go 目录。在该目录下,我创建了以下类似的 server.go 文件。
package main
import (
"fmt"
"net/http"
)
func main() {
http.HandleFunc("/", handler)
http.ListenAndServe(":8080", nil)
}
func handler(w http.ResponseWriter, r *http.Request) {
fmt.Fprintf(w, "Your url path is %s", r.URL.Path[1:])
}
3. 启动服务器
我试图在2状态下停止或附加容器,并添加端口映射,但是只找到了先提交镜像再重新启动新容器的方法。
为了进行端口映射,需要再次commit image。
まずはコンテナから抜ける
# exit
commit (pushしてもよい)
$ docker commit [container ID] [dockerhub username]/goserver
b. 在新创建的镜像中添加了端口映射规则后,在守护模式下启动。
$ docker run -p 8080:8080 -td [dockerhub username]/goserver
c. 进入启动的容器
$ docker exec -it [container ID] /bin/bash
执行服务器脚本
# go run server.go
e. 访问http://localhost:8080
使用Dockerfile来搭建服务器。
在前3个项目中,我已经能够使用Docker搭建Go的Web服务器了。
但是,我遇到了两个问题:
1. 它已经包含了vim编辑器。
2. 它还包含了src文件(因为Go是一种编译语言,所以只需要执行文件就可以了)。
在构建Docker镜像时,我们希望只包含必要的部分,并保持尽可能简单。否则,会浪费启动时间和多个容器的资源。
从docker镜像中移除vim。
我需要一个编辑器才能进行开发,但是除了Vim之外,我想抛弃它。
这次我试着将在本地创建的server.go文件放入Docker中来组织。
准备Dockerfile。
FROM golang
MAINTAINER vankobe
ADD . /go/src/
EXPOSE 8080
CMD ["/usr/local/go/bin/go", "run", "/go/src/server.go"]
b. 运行build
# ビルドを実行するフォルダの中
$ ls
Dockerfile server.go
$ docker build .
...
(実行ログ)
...
Successfully built a176df9f6c3e
c. 使用已构建的镜像来启动容器
(如果容器启动失败,可能是CMD参数等设置有误。可以使用docker logs查看日志以查找问题的原因)
$ docker run -p 8080:8080 -td a176df9f6c3e
访问 http://localhost:8080
将4.2中的源代码文件从Docker镜像中排除。
由于 Go 是一种编译语言,所以只需有编译后的可执行文件即可。
这次我尝试使用 GoLang 图像创建的可执行文件,将其复制到 Alpine 镜像上并执行。
a. 更改文件名
我之前将 server.go 放在 /go/src 中,现在我会将 main.go 放在 /go/src/server 中。
首先,将 server.go 重命名为 main.go。
$ mv server.go main.go
$ ls
Dockerfile main.go
b. 准备一个Dockerfile
FROM golang
MAINTAINER vankobe
ADD . /go/src/server
RUN go install server
FROM alpine
COPY --from=0 /go/bin/server .
ENV PORT 8080
CMD ["./server"]
c. 进行构建
$ docker build .
...
(実行ログ)
...
Successfully built 19ace85b6019
使用构建的镜像启动容器。
$ docker run -p 8080:8080 -td 19ace85b6019
e. 访问 http://localhost:8080
当您进入启动的容器中,您会发现除了可执行文件外,其他文件并没有被复制过。
最后
AWS和GCP都加强了对容器的支持功能。
由于GCP的container-engine-samples中有许多示例,我打算尝试一下。
(当我在写的过程中,发现这个示例与上述样本内的hello-app几乎相同。我感到有点失望。)
用Docker享受生活。
附录
在当前目录中进行ADD操作会导致Dockerfile也被复制,因此建议准备.dockerignore。
Dockerfile