Gin实践 连载七 将golang应用部署到docker

docker介绍

在这里简单介绍下Docker,建议深入学习
Docker 是一个开源的轻量级容器技术,让开发者可以打包他们的应用以及应用运行的上下文环境到一个可移植的镜像中,然后发布到任何支持Docker的系统上运行。 通过容器技术,在几乎没有性能开销的情况下,Docker 为应用提供了一个隔离运行环境

  • 简化配置
  • 代码流水线管理
  • 提高开发效率
  • 隔离应用
  • 快速、持续部署

golang

一、编写Dockerfile

项目根目录创建 Dockerfile 文件,写入内容

FROM golang:1.18

WORKDIR /src/gin_blog

COPY . /src/gin_blog

ENV GO111MODULE=on
ENV GOPROXY="https://goproxy.cn"
RUN go mod tidy
RUN go build .

EXPOSE 8000

ENTRYPOINT ["./gin_log"]

作用

golang:latest 镜像为基础镜像,将工作目录设置为 $GOPATH/src/go-gin-example,并将当前上下文目录的内容复制到 $GOPATH/src/go-gin-example 中
在进行 go build 编译完毕后,将容器启动程序设置为 ./go-gin-example,也就是我们所编译的可执行文件
注意 go-gin-example 在 docker 容器里编译,并没有在宿主机现场编译

说明

Dockerfile 文件是用于定义 Docker 镜像生成流程的配置文件,文件内容是一条条指令,每一条指令构建一层,因此每一条指令的内容,就是描述该层应当如何构建;这些指令应用于基础镜像并最终创建一个新的镜像
你可以认为用于快速创建自定义的 Docker 镜像
1. FROM
指定基础镜像(必须有的指令,而且必须是第一条指令)
2. WORKDIR
格式为 WORKDIR <工作目录路径>
使用 WORKDIR 指令可以来指定工作目录(或者称为当前目录),以后各层的当前目录就被改为指定的目录,如果目录不存在,WORKDIR 会帮你建立目录
3. COPY
格式:
COPY <源路径>... <目标路径>
COPY ["<源路径1>",... "<目标路径>"]
COPY 指令将从构建上下文目录中 <源路径> 的文件/目录复制到新的一层的镜像内的 <目标路径> 位置
4. RUN
用于执行命令行命令
格式:RUN <命令>
5. EXPOSE
格式为 EXPOSE <端口1> [<端口2>…]
EXPOSE 指令是声明运行时容器提供服务端口,这只是一个声明,在运行时并不会因为这个声明应用就会开启这个端口的服务
在 Dockerfile 中写入这样的声明有两个好处
帮助镜像使用者理解这个镜像服务的守护端口,以方便配置映射
运行时使用随机端口映射时,也就是 docker run -P 时,会自动随机映射 EXPOSE 的端口
6. ENTRYPOINT
ENTRYPOINT 的格式和 RUN 指令格式一样,分为两种格式
exec 格式:
<ENTRYPOINT> "<CMD>"
shell 格式:
ENTRYPOINT [ "curl", "-s", "http://ip.cn" ]
ENTRYPOINT指令是指定容器启动程序及参数

二、构建镜像

在gin_blog目录下执行:sudo docker build -t gin_blog .
该命令作用是创建/构建镜像,-t 指定名称为 gin-blog-docker,. 构建内容为当前上下文目录
执行结果:

......
go: downloading github.com/kr/text v0.2.0
go: downloading github.com/rogpeppe/go-internal v1.8.0
Removing intermediate container 98561ca7f5b5
 ---> 33f53945e296
Step 7/9 : RUN go build .
 ---> Running in 229d911348fd
Removing intermediate container 229d911348fd
 ---> e3adde861873
Step 8/9 : EXPOSE 8000
 ---> Running in 26df2f261f02
Removing intermediate container 26df2f261f02
 ---> 6255c0629227
Step 9/9 : ENTRYPOINT ["./gin_log"]
 ---> Running in 53855e2097f7
Removing intermediate container 53855e2097f7
 ---> 44f8f8bf076a
Successfully built 44f8f8bf076a
Successfully tagged gin_blog:latest

三、验证镜像

查看所有的镜像,确定刚刚构建的 gin_blog 镜像是否存在
sudo docker images

创建并运行一个容器

sudo docker run -it -p 8000:8000 --volume /home/mayanan/gin_blog/runtime:/src/gin_blog/runtime --name gin_blog gin_blog
容器名为gin_blog,将容器内的日志挂载出来,端口映射出来,以交互式终端启动运行。
输出结果:

 - using env:   export GIN_MODE=release
 - using code:  gin.SetMode(gin.ReleaseMode)

[GIN-debug] GET    /test                     --> gin_log/routers.InitRouter.func1 (3 handlers)
[GIN-debug] GET    /auth                     --> gin_log/routers/api/v1.GetAuth (3 handlers)
[GIN-debug] GET    /api/v1/tags              --> gin_log/routers/api/v1.GetTags (4 handlers)
[GIN-debug] POST   /api/v1/tags              --> gin_log/routers/api/v1.AddTag (4 handlers)
[GIN-debug] PUT    /api/v1/tag/:id           --> gin_log/routers/api/v1.EditTag (4 handlers)
[GIN-debug] DELETE /api/v1/tag/:id           --> gin_log/routers/api/v1.DeleteTag (4 handlers)
[GIN-debug] GET    /api/v1/articles          --> gin_log/routers/api/v1.GetArticles (4 handlers)
[GIN-debug] GET    /api/v1/article/:id       --> gin_log/routers/api/v1.GetArticle (4 handlers)
[GIN-debug] POST   /api/v1/article           --> gin_log/routers/api/v1.AddArticle (4 handlers)
[GIN-debug] PUT    /api/v1/article/:id       --> gin_log/routers/api/v1.EditArticle (4 handlers)
[GIN-debug] DELETE /api/v1/article/:id       --> gin_log/routers/api/v1.DeleteArticle (4 handlers)

服务启动成功。

思考

虽然应用已经能够跑起来了
但如果对 Golang 和 Docker 有一定的了解,我希望你能够想到至少2个问题

  • 为什么 gin_blog 占用空间这么大?(可用 docker ps -as | grep gin_blog 查看)

创建超小的容器镜像

Q: 第一个问题,为什么这么镜像体积这么大
A: FROM golang:1.18拉取的是官方golang镜像,包括golang的编译和运行环境,外加一堆GCC、build工具,相当齐全
这是有问题的,我们可以不在Golang容器中现场编译的,压根用不到那些东西,我们只需要一个能够运行可执行文件的环境即可

构建Scratch镜像

Scratch镜像,简洁、小巧,基本是个空镜像

  1. 修改Dockerfile
FROM scratch

WORKDIR /src/gin_blog

COPY . /src/gin_blog

EXPOSE 8000

CMD ["./gin_log"]
  1. 编译可执行文件
    CGO_ENABLED=0 GOOS=linux go build -a -installsuffix cgo -o gin_blog .
    编译所生成的可执行文件会依赖一些库,并且是动态链接。在这里因为使用的是 scratch 镜像,它是空镜像,因此我们需要将生成的可执行文件静态链接所依赖的库
  2. 构建镜像
    sudo docker build -t gin_blog .
  3. 通过镜像创建容器并启动
    sudo docker run -it -p 8000:8000 --name gin_blog -v /home/mayanan/gin_blog/runtime:/src/gin_blog/runtime gin_blog
    同时将应用的日志数据挂载出来。
  4. 此时再次查看容器所占用的空间
    sudo docker ps -as|grep gin_blog
7060bab18b26   gin_blog       "./gin_blog"             3 minutes ago   Up 3 minutes               0.0.0.0:8000->8000/tcp, :::8000->8000/tcp   gin_blog       0B (virtual 17.1MB)

仅仅只占了17.1兆。

posted @ 2022-09-13 09:55  专职  阅读(664)  评论(0编辑  收藏  举报