docker部署Go web项目

412 阅读3分钟

‌‌

写在前面

‌‌‌  本文的Go web项目代码摘自于 汪明《Go并发编程实战》一书中的第十一章。Docker部署过程借鉴了juejin.cn/post/689904… 这篇文章。但在实际部署过程中遇到一些文件路径问题,通过debug最终使得Go web项目能够在所有终端通过ip:port访问,在此记录一下踩坑点,希望对大家有所帮助。

部署过程


代码目录结构
Pasted image 20230117130728.png 展示server.go的代码 ```go package main

import ( "net/http" "fmt" "myweb/web" ) func main() { web.RegisterRouter() //在static.go中定义 fmt.Println("server start") err := http.ListenAndServe(":8080", nil) //监听的端口号 if err != nil { fmt.Println("ListenAndServe: ", err) } }



`server.go`中包含`main`函数,通过调用`web`目录下的文件来实现服务。另外`index.html`是默认访问的静态资源,当url请求不是`index.html`时便会返回`error.html``font``css``images``js`目录下都存放一些静态文件以供`index.html`调用访问。最笨的办法是将所有的源码都打包进一个Docker镜像中。

编写一个Dockerfile文件
```Dockerfile
FROM golang:alpine   //设置基础镜像,会提供go的运行环境

RUN mkdir /build

#将代码复制到/build中,此时.是docker build命令所指定的目录,也就是Dockerfile所在目录
COPY . /build

#当前工作目录变为/build,后面的. 指代的便是/build
WORKDIR /build 

#将代码编译成二进制可执行文件
RUN go build -o app .

#暴露端口
EXPOSE 8080

#需要运行的命令
CMD ["/build/app"]

在实际编写过程中,如果碰到“源码正常运行,上了Docker出现 # panic: runtime error: invalid memory address or nil pointer dereference ”,此时就要考虑是不是文件目录是否放错。如果不对位,这个错误其实在对应点上fmt.Println(err)便是找不到指定文件。所以编写Dockerfile一定要根据自己的文件结构去编写。

docker build . -t goweb_app:1.1

上述命令中,由于这条docker build运行在含有Dockerfile的目录下,所以只需要.(表示当前目录)。 -t指定了镜像的名称。可以通过docker build --help查看一些参数的作用。 注意,一般在构建镜像的时候都会打上版本号(Tag),每重新构建一次镜像便更新tag。我们来看下上述Dockerfile编出来的镜像大小。

docker images //查看所有镜像

Pasted image 20230117133951.png

两阶段构建镜像

Go编译之后得到的是一个二进制可执行文件,我们只要这个二进制文件,以及静态文件即可(有的项目还可能有配置文件)。

FROM golang:alpine as builder

# 容器环境变量添加,会覆盖默认的变量值
ENV GO111MODULE=on\
    GOOS=linux \
    CGO_ENABLED=0 \
    GOARCH=amd64

WORKDIR /build
COPY . .
RUN  go build -o app .

FROM scratch
WORKDIR /secbuild

COPY --from=builder /build/app /secbuild
COPY --from=builder /build/index.html /secbuild
COPY --from=builder /build/error.html /secbuild/error.html
COPY --from=builder /build/css /secbuild/css
COPY --from=builder /build/js /secbuild/js
COPY --from=builder /build/images /secbuild/images
COPY --from=builder /build/font /secbuild/font

EXPOSE 8080
CMD [ "/secbuild/app" ]

这里面坑比较多,尝试很久才这样的写法才能正常运行。 Pasted image 20230117185045.png 可以看到,第一阶段的镜像有339MB,第二阶段的镜像只有8.6MB。当我们删除掉基础镜像后,仅仅使用8.6MB的镜像创建并运行容器,看看能否正常运行。 Pasted image 20230117185817.png

我们看看在手机端输入http://云主机ip:8080/index.html请求时,看看能否正常响应。

IMG_7505(20230117-185913).jpg

页面正常返回,大功告成!以后就按照上面的模式写多阶段Dockerfile了! 另外,如果在宿主机(不是云主机,而是去ssh这个云主机的主机)输入http://localhost:8080/index.html时,显示localhost拒绝连接:

Pasted image 20230117190248.png 则可以在vscode上的port forward上加上8080端口,这样就会将请求和响应通过本地8080端口和云主机8080端口之间进行转发 Pasted image 20230117190529.png

在本地浏览器输入http://localhost:8080/index.html,返回如下: Pasted image 20230117190613.png

Dockerfile的编写,以及在浏览器上测试网页坑确实还挺多的,共勉!