随着新的一年即将来临,我们都对2021年会带来些什么感到疑惑。与每年一样,看看那里有什么技术以及学习什么会很有趣。
但是在如此广阔的技术海洋中,你如何选择下一步要学习的内容
几乎不管你对编程的兴趣在哪里,Go中都将有一种方法来实现它。就个人而言,我喜欢在学习语言时深入研究项目,并且理想情况下直接研究该项目对学习语言很有帮助。
不过今天不是来谈论如何学习go语言的教程,当然后面也会增加go语言的教程,今天先来分享一下如何在kubernetes部署发布go应用程序,那么对于当前谈论到的云原生技术市场,国内普遍公司都在使用kubernetes、以及docker等go开发的核心技术,之前记得面试一家某公司谈论到公司所有的技术栈后端都是使用的go去开发的,当时我没想法这几年几乎很多公司已经在web后端都使用起了go,看来也有由于kubernetes技术影响了很多的技术架构进行衍生以及替换公司原有的技术
好吧,不过回归正题,那么对于一些公司当中的语言比如使用了go开发的,那么我们如何迁移到kubernetes当中呢,是不是和前面我提到的文章相同呢,那么如果你对此还有些疑惑,你可以翻到前面的文章进行学习,在kubernetes运行与发布node.js、spring boot应用,如果你还没有学习,建议先去看看前面的文章,因为后面发布的文章都会牵连前面的技术会更新文章,以及后面涉及到的gitops的教程实现CI/CD的教程
借着这些疑惑,我们应该如何实现这种将go的应用程序迁移到k8s当中呢?
这里会提到一些go的技术,下面会演示一个go的示例,如果你对go还不熟悉,不过也不要紧,这里会将一些go的开发技巧以及如何部署的细节演示出来,便于你如果公司突然有这么一个go的应用不知道如何迁移部署到k8s当中了。
下面大致的步骤是这样
- 我会详细带你构建一个用Go编写的示例应用程序
- 因为go属于编译型语言,这里我们会先进行编译,不过这里和java的应用不一样,java需要jdk的环境即可,而go不是jar包
- 这里将使用Docker对该应用程序进行容器化
- 将其部署到Kubernetes集群,并创建一个负载平衡器,该负载平衡器将作为应用程序的面向公众的入口点使之我们去访问该应用程序。
先决条件如果你有goland或者vscode更好了,如果没有的话,或者使用linux当中的vim也是可以,另外你还要需要一个k8s环境,因为我们需要在goland去编写我们的代码,当然这里主要是交给你如何去使用它,另外为了本次环境也能在你的环境正常运行,我会将本次的示例打包放在gitee上,方便你自己去演示此次的示例,更快的学会如何在k8s中部署go的应用
1、安装go环境
在你的主机安装go的二进制包
这里我选择了最新的15.6的版本,如果你还没下载可以去到这里下载
https://golang.org/dl/
或者在你的linux主机下载这个,安装完解压之后你可以看到go的版本
[root@m1 go-k8s]# wget https://dl.google.com/go/go1.15.6.linux-amd64.tar.gz
[root@m1 go-k8s]# tar xf go1.15.6.linux-amd64.tar.gz -C /usr/local/
[root@m1 go-k8s]# export PATH=$PATH:/usr/local/go/bin
[root@m1 go-k8s]# go version
go version go1.15.6 linux/amd64
下面是我们本次示例的目录,安装包可以通过上面的下载,另外我创建了一个工作目录,放置go的代码以及制作go应用的Dockerfile
[root@m1 go-k8s]# ls
go1.15.6.linux-amd64.tar.gz go-web
[root@m1 go-k8s]# cd go-web/
[root@m1 go-web]# ls
Dockerfile go-web.go
下面我们先来分析下我们的go-web.go
2、编写go程序
[root@m1 go-web]# cat go-web.go
package main
import (
"fmt"
"net/http"
)
func Cloud(kube http.ResponseWriter, cto *http.Request) {
fmt.Fprint(kube, "欢迎你加入云原生CTO圆桌派,\n这里包含了Cloud native所有的技术栈,\n以及技术答疑以及好玩的云原生开发运维技巧,\n如果你还没加入,那么阅读完本教程之后末尾扫码即可加入,\n另外微信公众号kubecto也会为你提供云原生开发运维教程,只需在微信搜索kubecto即可关注")
}
func setuproute() {
http.HandleFunc("/",Cloud)
}
func main() {
fmt.Println("go web app start on port 3009 ")
setuproute()
http.ListenAndServe(":3009",nil)
}
你要知道任何Go源文件中的第一行始终是一条package语句,用于定义文件所属的代码束。对于像这样的可执行文件,该package语句必须指向该main软件包
对应代码段
package main
接下来,添加一条import语句,你可以在其中列出该应用程序所需的所有库。这里的includefmt和net/http,提供格式化的文本输入和输出,以及提供HTTP客户端和服务器的实现:
对应代码段
import (
"fmt"
"net/http"
)
接下来,定义一个Cloud包含两个参数的函数:http.ResponseWriter和的指针http.Request。在Go中,ResponseWriter接口用于构造HTTP响应,而接口是http.Request表示传入请求的对象。因此,此块读取传入的HTTP请求,然后构造一个响应:
对应代码段
func Cloud(kube http.ResponseWriter, cto *http.Request) {
fmt.Fprint(kube, "欢迎你加入云原生CTO圆桌派,\n这里包含了Cloud native所有的技术栈,\n以及技术答疑以及好玩的云原生开发运维技巧,\n如果你还没加入,那么阅读完本教程之后末尾扫码即可加入,\n另外微信公众号kubecto也会为你提供云原生开发运维教程,只需在微信搜索kubecto即可关注")
}
此后,添加一个setuproute函数,该函数会将传入的请求映射到其预期的HTTP处理程序函数。在此setuproute函数的主体中,将/路由映射添加到新定义的Cloud函数。这告诉应用程序输出欢迎你加入云原生CTO圆桌派,\n这里包含了Cloud native所有的技术栈,\n以及技术答疑以及好玩的云原生开发运维技巧,\n如果你还没加入,那么阅读完本教程之后末尾扫码即可加入,\n另外微信公众号kubecto也会为你提供云原生开发运维教程,只需在微信搜索kubecto即可关注"这样则对对应端点的请求也要打印消息:
对应代码段:
func setuproute() {
http.HandleFunc("/",Cloud)
}
最后,添加以下main功能。这将打印出一个字符串,指示你的应用程序已启动。然后,它将setupRoutes在侦听并在port上服务您的Go应用程序之前调用该函数3009。
接下来,使用以下go run命令运行该应用程序。这将编译main.go文件中的代码,现在它可以在你的本地环境运行它:
[root@m1 go-web]# go run go-web.go
go web app start on port 3009
此输出确认该应用程序按预期运行。它会无限期运行,但是,请按CTRL + C关闭它。
在本指南中,你将使用此示例应用程序来实验Docker和Kubernetes。为此,请继续阅读以了解如何使用Docker容器化你的go应用程序并部署到kubernetes中。
3、对Go应用进行Docker化
在当前状态下,刚创建的Go应用程序仅在开发服务器上运行。在此步骤中,将通过使用Docker对其进行容器化来使此新应用程序可移植到k8s中。这将使其能够在支持Docker容器的任何机器上运行。我们将构建一个Docker镜像并将其推送到Docker Hub上的中央公共存储库。这样,你的Kubernetes群集可以拉回镜像并将其部署为群集内的容器,当然如果你有harbor仓库更好,可以在你的私有仓库存储镜像
容器化应用程序的第一步是创建一个名为Dockerfile的特殊脚本。Dockerfile通常包含按顺序运行的指令和参数的列表,以便在基础镜像上自动执行某些操作或创建一个新镜像。
下面继续分析dockerfile
[root@m1 go-web]# cat Dockerfile
FROM golang:1.12.0-alpine3.9
WORKDIR /app
COPY . /app
RUN go build -o go-web .
EXPOSE 3008
ENTRYPOINT ["/app/go-web"]
首先在文件顶部,指定Go应用所需的基础镜像 并制定容器的工做目录 将当前目录下的go-web.go程序放到容器的app下 运行命令在容器内编译-o强制执行把构建的可执行文件写入到目标文件go-web中 .指定当前工作目录下的go-web.go文件 一般我们会在dockerfile expose出容器的端口,方便维护 entrypoint来启动/app/go-web应用程序
现在,你已经Dockerfile在项目的根目录中有了它,你可以使用以下docker build命令基于它创建一个Docker镜像。
并通过docker run 去测试查看我们的应用是否通过并发布出去
[root@m1 go-web]# docker build -t zhaocheng172/go-web:v8 .
[root@m1 go-web]# docker run -it -p 3001:3009 --name go-web9 zhaocheng172/go-web:v8
go web app start on port 3009
很不错这样我们已经通过我们的dockerfile将我们的go应该容器化并发布出去,下面我们接下来将它推送到k8s中
首先我们需要将它上传到我们的镜像仓库中,方便我们在k8s去使用这个镜像
[root@m1 go-web]# docker push zhaocheng172/go-web:v8
4、部署以及发布go应用
restful资源构成了Kubernetes系统中的所有持久性实体,在这种情况下,它们通常被称为Kubernetes对象。将Kubernetes对象视为提交给Kubernetes的工作订单会很有帮助
一种Kubernetes对象(称为部署)是一组相同的,无法区分的Pod。在Kubernetes中,pod是一个或多个容器的组合,这些容器能够通过同一共享网络进行通信并与同一共享存储进行交互。部署一次运行多个父应用程序的副本,并自动替换任何失败的实例,以确保您的应用程序始终可用于满足用户请求。
在此步骤中,你将为部署创建一个Kubernetes对象描述文件,也称为清单。此清单将包含将Go应用程序部署到集群所需的所有配置详细信息。
对于像这样的小型项目,我已经将它们保留在一个单独的目录中可以最大程度地减少复杂性,也能更好的让你了解中间做了哪些事情。
[root@m1 k8s]# cat go-web-deployment.yaml
---
apiVersion: apps/v1
kind: Deployment
metadata:
name: go-web-app
spec:
replicas: 2
selector:
matchLabels:
name: go-web-app
template:
metadata:
labels:
name: go-web-app
spec:
containers:
- name: application
image: zhaocheng172/go-web:v8
imagePullPolicy: IfNotPresent
ports:
- containerPort: 3009
---
apiVersion: v1
kind: Service
metadata:
name: go-web-service
spec:
type: NodePort
ports:
- name: http
port: 3009
targetPort: 3009
nodePort: 30009
selector:
name: go-web-app
下面解释一下所用到的细节方面 Kubernetes API的不同版本包含不同的对象定义,因此,在此文件的顶部,必须定义apiVersion用于创建此对象的对象。就本教程而言,你将使用apps/v1分组,因为该分组包含创建部署所需的许多核心Kubernetes对象定义。在下面添加一个字段,apiVersion描述kind您正在创建的Kubernetes对象。
然后metadata为你的部署定义。metadata每个Kubernetes对象都需要一个字段,因为该字段包含诸如name对象唯一性之类的信息。这name很有用,因为它使你可以区分不同的部署,并使用易于理解的名称来识别它们
接下来,spec每个Kubernetes对象都需要一个字段,但是对于每种对象类型,其精确格式都不同。在部署的情况下,它可以包含诸如你要运行的副本数之类的信息。在Kubernetes中,副本是你要在集群中运行的Pod数量。在此,将的数量设置replicas为2
接下来,创建一个selector嵌套在该spec块下的块。这将用作你的pod的标签选择器。Kubernetes使用标签选择器来定义部署如何查找其必须管理的Pod。
在此selector块中,定义matchLabels并添加name标签。本质上,该matchLabels字段告诉Kubernetes部署适用于哪些Pod。在此示例中,部署将应用于名称为的任何Pod go-web-app
之后,添加一个template块。每个部署都使用template块中指定的标签创建一组Pod 。此块中的第一个子字段是metadata包含labels将应用于此部署中的所有Pod的子字段。这些标签是键/值对,用作标识Kubernetes对象的属性。以后定义服务时,可以指定要将带有此name标签的所有Pod分组到该服务下。将此name标签设置为go-web-app:
该template块的第二部分是该spec块。这与spec你之前添加的块不同,因为该块仅适用于由该template块创建的Pod ,而不适用于整个部署。
在此spec块中,添加一个containers字段,然后再次定义一个name属性。该name字段定义此特定部署创建的任何容器的名称。在此之下,定义image你要下拉并部署的对象。确保更改image为你自己的Docker Hub用户名或者你的私有镜像的地址。
之后,添加一个imagePullPolicy字段集,IfNotPresent该字段集将指示部署没有本地没有才去拉取镜像。然后,最后添加一个ports块。在containerPort此处定义应该与Go应用程序侦听的端口号匹配的。在这种情况下,端口号是3009
在---下面中,你将会创建另一种Kubernetes对象,该对象将管理如何访问新部署中存在的Pod。此服务将创建一个负载平衡器,该负载平衡器将随后公开一个IP地址,并且对该IP地址的请求将分发到您部署中的副本。该服务还将处理端口转发规则,以便你可以通过HTTP访问应用程序。
现在已经成功部署了Kubernetes,则可以将应用程序暴露给外界了。为此,你需要定义另一种Kubernetes对象:service。该服务将在群集的所有节点上公开相同的端口。然后,你的节点会将该端口上的所有传入流量转发到运行你的应用程序的Pod。
这里几乎和上面一样,其次然后添加一个ports块,你将在其中定义希望访问应用程序的方式。嵌套在此块中,添加以下字段:
name, 指向 http port,指向端口 3009 targetPort,指向端口 3009 这将需要在端口传入的HTTP请求3009,并将其转发到targetPort的3009。这targetPort是你的Go应用程序运行所在的端口:
最后,selector像在deployments.yml文件中一样添加一个块。此selector块很重要,因为它映射了命名go-web-app为该服务的所有已部署的Pod
这样,你就创建了一个Kubernetes服务以及一个负载平衡器,从而为你提供了一个稳定的应用程序入口点。
[root@m1 k8s]# kubectl get po,svc |grep -w go-web
pod/go-web-app-64b7999598-42mr2 1/1 Running 0 2m43s
pod/go-web-app-64b7999598-tdxw6 1/1 Running 0 2m43s
service/go-web-service NodePort 10.108.36.145 <none> 3009:30009/TCP 2m43s
现在你可以使用30009在你的本地电脑进行访问我们在k8s运行的go应用了,显然当我们使用k8s去管理应用更容易去维护与发布
结论
在本教程中,你已经构建了Go应用程序,并使用Docker对其进行了容器化,然后将其部署到Kubernetes集群中。然后,你创建了一个负载平衡器,为该应用程序提供了一个弹性的入口点,以确保即使集群中的一个节点发生故障,它也将保持高可用性。你可以使用本教程将自己的Go应用程序部署到Kubernetes集群
后续会通过traefik/ingress-nginx发布我们之前的spring boot/node.js以及现在的go-web应用以及gitops实现CI/CD欢迎继续关注公众号讯息
有疑问加站长微信联系(非本文作者)