文档章节

利用docker来部署go应用程序

罗布V
 罗布V
发布于 02/27 00:19
字数 2156
阅读 433
收藏 0

利用docker实现go程序的快速部署

最近很长一段时间一直通过各种渠道去了解国内外有关devops方面的实践,感受很多的知识点都特别的分散,所以想通过系统的整理来巩固相应的知识体系。接下来会撰写一系列有关容器化的文章。
1、 利用docker部署一个简单的go程序,并且利用阿里云的平台,进行镜像的生成
2、 利用docker-compose部署一个复杂的go程序,同时部署包含多个不同子容器的集成
3、 利用gitlab和Harbor来做ci/cd

容器是独立的软件包,能够将应用程序以及所有的依赖项、工具、库、配置文件 以及运行该应用程序所需要的所有的其他内容捆绑在一起。
通过docker可以实现将您 的应用环境从运行的物理操作系统上面抽象一层虚拟操作环境。从而保证你的程序从开发到测试以及现场的部署,保证了环境 的一致性问题。

创建一个简单的Go项目

在开始演习之前,我们通过下面命令来创建一个新的目录,接下来我们所有的文件都将存放在这个目录当中。

mkdir go-docker
在创建完成目录之后,我们需要用go的原生命令来初始化相应的go模块。go mod是go11新增加的功能,在这之前出现很好几种模块化的解决方案,在go11之后官方终于给出了自己的解决方案.
cd go-docker
go mod init github.com/wenchangshou2/go-docker
我们现在创建一个简单的hello world的服务,通过下面的命令来创建一个新的文件 
touch hello_server.go

以下是hello_server.go的内容

package main

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

    "github.com/gorilla/mux"
    "gopkg.in/natefinch/lumberjack.v2"
)

func handler(w http.ResponseWriter, r *http.Request) {
    query := r.URL.Query()
    name := query.Get("name")
    if name == "" {
        name = "访客"
    }
    log.Printf("接收一个新的请求 %s\n", name)
    w.Write([]byte(fmt.Sprintf("Hello, %s\n", name)))
}

func main() {
    // 创建服务和root事件
    r := mux.NewRouter()

    r.HandleFunc("/", handler)

    srv := &http.Server{
        Handler:      r,
        Addr:         ":8080",
        ReadTimeout:  10 * time.Second,
        WriteTimeout: 10 * time.Second,
    }

    // 配置日志
    LOG_FILE_LOCATION := os.Getenv("LOG_FILE_LOCATION")
    if LOG_FILE_LOCATION != "" {
        log.SetOutput(&lumberjack.Logger{
            Filename:   LOG_FILE_LOCATION,
            MaxSize:    500, // 总大小
            MaxBackups: 3,
            MaxAge:     28,   //最长保存时间
            Compress:   true, //  压缩数据,默认关闭
        })
    }

    // 启动服务
    go func() {
        log.Println("启动服务")
        if err := srv.ListenAndServe(); err != nil {
            log.Fatal(err)
        }
    }()

    // 正常关闭
    waitForShutdown(srv)
}

func waitForShutdown(srv *http.Server) {
    interruptChan := make(chan os.Signal, 1)
    signal.Notify(interruptChan, os.Interrupt, syscall.SIGINT, syscall.SIGTERM)

    // 阻塞,直到接收到信号
    <-interruptChan

    ctx, cancel := context.WithTimeout(context.Background(), time.Second*10)
    defer cancel()
    srv.Shutdown(ctx)

    log.Println("结束退出")
    os.Exit(0)
}

通过下面的命令来构建一个应用程序

wcs@iMac  ~/demo/go-docker  go build  ✔  >4950  23:22:27
go: finding github.com/gorilla/mux v1.7.4
go: downloading github.com/gorilla/mux v1.7.4
go: extracting github.com/gorilla/mux v1.7.4
go: downloading gopkg.in/natefinch/lumberjack.v2 v2.0.0
go: extracting gopkg.in/natefinch/lumberjack.v2 v2.0.0
通过go build,会自动下载需要的包,并且生成相应的可执行程序,通过下面的命令运行
wcs@iMac  ~/demo/go-docker  ./go-docker  ✔  
2020/02/26 23:24:05 启动服务

现在我们尝试通过curl 来测试功能是否可用

wcs@iMac  ~  curl localhost:8080  ✔  4958 
Hello, 访客
wcs@iMac  ~  curl http://localhost:8080\?name\=Rajeev
Hello, Rajeev

通过DockerFile文件来定义docker 镜像文件

现在我们需要在上面的根目录下面新建一个文件,将文件的名称命名为Dockerfile.

# 构建该项目的基础镜像
FROM golang:latest

# 添加作者信息
LABEL maintainer="wcs <wenchangshou@gmail.com>"

# 设置当前的工作目录
WORKDIR /app

# 复制 go mod和sum 文件 
COPY go.mod go.sum ./

# 下载所有的依赖
RUN go mod download
# 复制当前目录源文件到工作目录下面

COPY . .
# 编译GO程序
RUN go build -o main .

# 通过EXPOSE对外暴露服务的端口号

EXPOSE 8080
# 通过下面的命令来运行可执行文件 
CMD ["./main"]

编译和运行docker镜像

上面我们已经定义了DockerFile,现在我们需要通过命令将DockerFile生成构建和运行相应的映像

编译镜像

docker build -t go-docker .

你懂的国内应该各种原因,访问会特别的慢,你可以利用aliyun和daocloud来进行回事。
通过下面的命令来查看镜像是否生成成功.

docker image ls

REPOSITORY TAG IMAGE ID CREATED SIZE
go-docker lates 7654e880c09b 2 minutes ago 826MB
golang latest c3474fb0f20e 15 hours ago 809MB

运行docker镜像

现在我们终端可以运行之前生成的镜像了

docker run -d -p 8888:8080 go-docker

3c80b9cb6b21a4fd50ea8b157ace4f3a9757e92b0e3cf9192639d30299d03d73

查看运行的容器

你可以通过下面的命令来查看正在运行的容器
docker container ls
CONTAINER ID IMAGE COMMAND CREATED STATUS PORTS NAMES
3c80b9cb6b21 go-docker "./main" 45 seconds ago Up 45 seconds 0.0.0.0:8888->8080/tcp quirky_shamir

测试容器功能

现在我们可以通过curl来测试应用是否正常

curl http://localhost:8888\?name\=wcs
Hello, wcs

停止容器

现在运行完成之后我们就可以停止相应的容器。在每次创建容器的时候都会产生一个唯一的id,那个id用来标识相应的容器,之后可以通过该id进行相应的操作

docker container stop 3c80b9cb6b21

挂载本地目录到docker镜像中

现在我们开始一个新的实例,在dockerfile里面提供了一个volume的字段,通过该字段可以定义容器内部的共享的目录。定义完成之后,你可以在创建容器的时候指定volume目录与本地目录的绑定。
在以下Dockerfile中,我们声明一个volume路径/app/logs。容器会将日志文件写入/app/logs/app.log。运行docker映像时,我们可以将宿主的目录挂载到该卷上。完成此操作后,我们将能够从宿主的已挂载目录访问所有日志文件。

# 构建该项目的基础镜像
FROM golang:latest

# 添加作者信息
LABEL maintainer="wcs <wenchangshou@gmail.com>"

# 设置当前的工作目录
WORKDIR /app

# 编译参数
ARG LOG_DIR=/app/logs
# 创建log目录
RUN mkdir -p ${LOG_DIR}

#环境变量
ENV LOG_FILE_LOCATION=${LOG_DIR}/app.log

# 复制 go mod和sum 文件 
COPY go.mod go.sum ./

# 下载所有的依赖
RUN go mod download
# 复制当前目录源文件到工作目录下面

COPY . .
# 编译GO程序
RUN go build -o main .

# 通过EXPOSE对外暴露服务的端口号

EXPOSE 8080
# 声明Volumes
VOLUME [${LOG_DIR}]
# 通过下面的命令来运行可执行文件 
CMD ["./main"]

我们重新编译一个新的镜像

docker build -t go-docker-voluume -f Dockerfile.volume

现在我们创建宿主将要绑定的目录

mkdir -p ~/logs/go-docker
docker run -d -p 8889:8080 -v ~/logs/go-docker:/app/logs go-docker-volume 
394433aa0804dd24443d65090006e8becbe2aa26a883efe4324e79d4e085e261

现在我们发现docker已经将日志写入到宿主对象的目录当中

tail -f ~/logs/go-docker/app.log

2020/02/26 16:01:38 启动服务

优化镜像

通过上面的示例,我们生成了二个镜像,但是你们仔细查看,会发现即使这么小功能的一个程序,也会占用很大的存储空间。
docker image ls  ✔  4992  00:04:52
REPOSITORY TAG IMAGE ID CREATED SIZE
go-docker-volume latest 0b534f6bceaf 4 minutes ago 826MB
go-docker latest 7654e880c09b 19 minutes ago 826MB
golang latest c3474fb0f20e 16 hours ago 809MB
仅golang:latest镜像就占用了809MB,,而我们生成程序也占用了826M的空间。
上面之所以这样大,是因为golang:latest里面包含了整个go的运行环境以及相应的编译环境,而我们的应用程序仅在编译时需要这些,在编译完成之后仅运行就可以。根据这些需求我们可以将原有的镜像拆分成多步,第一步是编译,之后我们可以通过Alpine linux来进行最小化运行。
Dockerfile.multistage


FROM golang:latest as builder

LABEL maintainer="wcs<wenchangshou@gmail.com>"

WORKDIR /app

COPY go.mod go.sum ./

RUN go mod download

COPY . .
RUN CGO_ENABLED=0 GOOS=linux go build -a -installsuffix cgo -o main .



# 开始一个新的步骤
FROM alpine:latest

RUN apk --no-cache add ca-certificates

WORKDIR /root/
# 复制上一阶段的预构建二进制文件
COPY --from=builder /app/main .

EXPOSE 8080

CMD ["./main"] 

现在我们生成新的镜像

docker build -t go-docker-optimized -f Dockerfile.multistage .

现在我们再看压缩后的镜像

docker image ls

REPOSITORY TAG IMAGE ID CREATED SIZE
go-docker-optimized latest ed8e431271dc 23 seconds ago 14.1MB
go-docker-volume latest 0b534f6bceaf 11 minutes ago 826MB
go-docker latest 7654e880c09b 27 minutes ago 826MB
golang latest c3474fb0f20e 16 hours ago 809MB
alpine latest e7d92cdc71fe 5 weeks ago 5.59MB
现在你惊讶的发现压缩后的镜像仅有14.1M

 

© 著作权归作者所有

罗布V
粉丝 13
博文 62
码字总数 51109
作品 0
温州
程序员
私信 提问
加载中

评论(0)

docker入门-基本概念(一)

Docker是什么 Docker 是一个开源的应用容器引擎,基于 Go 语言 并遵从 Apache2.0 协议开源。 Docker的应用场景 Web 应用的自动化打包和发布。 自动化测试和持续集成、发布。 在服务型环境中部...

风又奈何
2019/12/14
0
0
Docker EE 统一应用程序管理功能大揭秘,你想要的都在这里!

本文首发自“Docker公司”公众号(ID:docker-cn) 编译丨小东 每周一、三、五 与您不见不散! 在 DockerCon 上,我们演示了 Docker EE 全新的统一应用程序管理功能,该功能可以让组织通过 ...

docker公司
2018/06/25
0
0
Docker与虚拟机之间的关键差异原来是它

  【IT168 编译】是什么让Docker容器如此受欢迎?在某些情况下甚至比虚拟机更有魅力?   答案就是密度。   为什么这么说?它怎会如此重要?   在计算的背景下,密度指的是单个物理服务器...

it168网站
2017/03/16
0
0
【案例学习】两年打造150,000个容器,看PAYPAL的Docker实践之路

背景介绍 PayPal(贝宝)是美国eBay公司的全资子公司。1998年12月由Peter Thiel及Max Levchin建立,总部位于美国加利福尼亚州圣荷西市。PayPal致力于使金融服务大众化,让人们与企业能够参与到...

木环
2017/12/29
0
0
基于阿里云容器服务的微服务实践 - Part 1. 微服务与Docker

版权声明:本文为博主chszs的原创文章,未经博主允许不得转载。 https://blog.csdn.net/chszs/article/details/54945952 基于阿里云容器服务的微服务实践 基于阿里云容器服务的微服务实践 - ...

chszs
2017/02/09
0
0

没有更多内容

加载失败,请刷新页面

加载更多

如何从Joomla垃圾箱中删除文章

Joomla允许您删除文章,但是除非您采取其他步骤,否则它不会永久删除它们。 Joomla的垃圾桶类似于PC和Mac的垃圾桶。将项目发送到垃圾桶是可以撤消的操作。 在这个简短的教程中,我将向您展示...

六艺网络专注于Joomla
41分钟前
37
0
图解kubernetes命令执行核心实现

K8s中的命令执行由apiserver、kubelet、cri、docker等组件共同完成, 其中最复杂的就是协议切换以及各种流拷贝相关,让我们一起来看下关键实现,虽然代码比较多,但是不会开发应该也能看懂,祝你...

8小时
46分钟前
29
0
sh和bash之间的区别 - Difference between sh and bash

问题: When writing shell programs, we often use /bin/sh and /bin/bash . 在编写shell程序时,我们经常使用/bin/sh和/bin/bash 。 I usually use bash , but I don't know what's the d......

技术盛宴
58分钟前
39
0
spring - 使用profile来管理环境信息

程序一般都会有开发环境、测试环境以及线上环境,这些环境下程序运行依赖的基础一般不同,例如在有数据源访问的程序中,开发时可能使用了嵌入式数据库,而到测试环境上会使用独立的mysql,正...

閒散人員
今天
21
0
如何实现项目流程自动化

多人协作复杂的任务,团队成员间的分工和沟通就非常必要。现在Zoho projects 项目管理软件中,配合使用蓝图功能,讲让工作事半功倍。 蓝图功能可以解决繁琐的邮件沟通问题,并使任务更加有序...

Zoho云服务
今天
37
0

没有更多内容

加载失败,请刷新页面

加载更多

返回顶部
顶部