业务应用介绍

go工程代码如下,使用到了第三方http框架gin。

  1. package main
  2. import (
  3. "github.com/gin-gonic/gin"
  4. "net/http"
  5. )
  6. func main() {
  7. r := gin.Default()
  8. r.GET("/", func(c *gin.Context) {
  9. c.JSON(http.StatusOK, gin.H{
  10. "code": 0,
  11. "message": "success",
  12. "data": "hello world",
  13. })
  14. })
  15. r.GET("/hello", func(c *gin.Context) {
  16. c.JSON(http.StatusOK, gin.H{
  17. "code": 0,
  18. "message": "success",
  19. "data": "world",
  20. })
  21. })
  22. r.GET("/ping", func(c *gin.Context) {
  23. c.JSON(http.StatusOK, gin.H{
  24. "code": 0,
  25. "message": "success",
  26. "data": "pong",
  27. })
  28. })
  29. r.Run(":8080")
  30. }

这个go 开发的 web 应用会监听 8080 端口,开放3个api

  1. GET /
  2. GET /hello
  3. GET /ping
  4. Listening and serving HTTP on :8080

Dockerfile 文件 如下

  1. FROM registry.cn-beijing.aliyuncs.com/baxiang/golang:1.14 as build
  2. ENV GO111MODULE=on
  3. ENV GOPROXY=https://mirrors.aliyun.com/goproxy/
  4. ENV GOBUILDPATH=github.com/baxiang/hello-world
  5. RUN mkdir -p /go/src/${GOBUILDPATH}
  6. COPY ./ /go/src/${GOBUILDPATH}
  7. RUN cd /go/src/${GOBUILDPATH} && CGO_ENABLED=0 GOOS=linux GOARCH=amd64 go install -v
  8. FROM alpine as dev
  9. WORKDIR /hello-wordld
  10. COPY --from=build /go/bin/hello-world ./hello-world
  11. EXPOSE 8080
  12. CMD ["./hello-world"]

将上面工程打包成成docker镜像 地址是registry.cn-beijing.aliyuncs.com/baxiang/hello-world:v1.0

部署Deployment

要让这个 web 应用的镜像在 k8s 中运行,我们首先要定义一个 deployment 资源。
通过创建deploy.yaml来描述 deployment 资源:

  1. apiVersion: apps/v1
  2. kind: Deployment
  3. metadata:
  4. name: myapp
  5. spec:
  6. replicas: 1
  7. selector:
  8. matchLabels:
  9. app: myapp
  10. template:
  11. metadata:
  12. labels:
  13. app: myapp
  14. spec:
  15. containers:
  16. - name: myapp
  17. image: registry.cn-beijing.aliyuncs.com/baxiang/hello-world:v1.0
  18. ports:
  19. - containerPort: 8080

其中:

  • image 属性:就是这个 java web 应用的镜像地址;
  • replicas 属性:代表这个应用只部署一份;

通过下面的命令执行:

  1. $ kubectl apply -f ~/deploy.yaml

完成后,你可以通过下面的命令查看刚才部署的 pod:

  1. $ kubectl get pod

看到如下提升代表应用部署完成,注意其中的 status 字段。只有 Running 才是运行中的状态哦,如果是 ContainerCreating 代表服务容器正在创建中,需要等待一段时间才能使用

  1. NAME READY STATUS RESTARTS AGE
  2. myapp-deployment-5cd4d7c78d-lxvcw 1/1 Running 0 12s

至此,我们已经完成了应用本身的部署,下面我们看下如何在 k8s 里配置“服务”;

部署服务

由于 deployment 是一个弹性组件,其管理的应用实例不是固定的,而是可以任意伸缩。这带来了很多的好处,例如可以支持弹性伸缩、滚动更新等等。
但是相反的,这也会导致应用实例IP不固定,从访问者的角度我们不可能每次去查找当前的应用实例。
所以,为了能提供稳定的访问入口,我们还需要部署“服务”来接收请求,并屏蔽内部的弹性机制。
部署服务,我们继续 yaml 文件的方式操作,创建 service.yaml:

  1. apiVersion: v1
  2. kind: Service
  3. metadata:
  4. name: myapp-service
  5. spec:
  6. selector:
  7. app: myapp
  8. type: NodePort
  9. ports:
  10. - port: 8080
  11. targetPort: 8080
  12. protocol: TCP

我们看到 Service 的定义相对简单很多,其中有几个关键属性需要说明:

  • selector,这是一个选择器,通过 name=myapp 这个条件来选择需要代理的服务
  • ports,这里定义了服务自身暴露的端口和需要访问的应用的端口

继续通过 kubectl 命令执行:

  1. kubectl apply -f ~/service.yaml

然后通过下面的命令查看刚才部署的 service:

  1. $ kubectl get service
  2. NAME TYPE CLUSTER-IP EXTERNAL-IP PORT(S) AGE
  3. myapp-service NodePort 10.102.180.254 <none> 8080:30194/TCP 158m

我们采用的NodePort的形式 因此我们也可以在当前节点上访问我们的服务,根据上面我们获取的sevice信息8080映射到节点上的端口是30194

  1. $ curl localhost:30194
  2. {"code":0,"data":"hello world","message":"success"}
  3. $ curl localhost:30194/hello
  4. {"code":0,"data":"world","message":"success"}
  5. $ curl localhost:30194/ping
  6. {"code":0,"data":"pong","message":"success"}

配置 ingress

k8s 是一个集群,deployment、service 都是集群内部的资源,他们通过一个内部虚拟网络互相访问。
但是对于外部的用户,这些所有的资源都是不可见的,所以我们还需要配置一个外部访问的入口到 service 的映射规则,从而将内部服务暴露出去。

安装NGINX ingress Controller

  1. kubectl apply -f https://raw.githubusercontent.com/kubernetes/ingress-nginx/master/deploy/static/provider/cloud/deploy.yaml

或者使用

  1. $ helm repo add ingress-nginx https://kubernetes.github.io/ingress-nginx
  2. $ helm repo update
  3. $ helm install ingress-nginx ingress-nginx/ingress-nginx --debug

这里我们就需要使用 ingress 的来实现服务对外暴露的需求。
我们继续使用 yaml 来定义 ingress 规则:

  1. apiVersion: networking.k8s.io/v1beta1
  2. kind: Ingress
  3. metadata:
  4. name: myingress
  5. labels:
  6. name: myingress
  7. annotations:
  8. nginx.ingress.kubernetes.io/rewrite-target: /$1
  9. spec:
  10. rules:
  11. - http:
  12. paths:
  13. - path: /myapp/(.*)
  14. backend:
  15. serviceName: myapp-service
  16. servicePort: 8080

如果出现错误

  1. Warning: networking.k8s.io/v1beta1 Ingress is deprecated in v1.19+, unavailable in v1.22+; use networking.k8s.io/v1 Ingress
  2. Error from server (InternalError): error when creating "ingress.yaml": Internal error occurred: failed calling webhook "validate.nginx.ingress.kubernetes.io": an error on the server ("") has prevented the request from succeeding

修改成如下

  1. apiVersion: networking.k8s.io/v1
  2. kind: Ingress
  3. metadata:
  4. name: myingress
  5. labels:
  6. name: myingress
  7. annotations:
  8. nginx.ingress.kubernetes.io/rewrite-target: /$1
  9. spec:
  10. rules:
  11. - http:
  12. paths:
  13. - path: /myapp/(.*)
  14. pathType: Prefix
  15. backend:
  16. service:
  17. name: myapp-service
  18. port:
  19. number: 8080

继续通过 kubectl 命令执行:

  1. kubectl apply -f ~/ingress.yaml

然后通过下面的命令查看刚才部署的 service:

  1. kubectl get ingress

我们会看到下面的反馈信息:

  1. $ kubectl get ingress
  2. NAME CLASS HOSTS ADDRESS PORTS AGE
  3. myingress <none> * localhost 80 149m

通过这个返回值信息,我们可以看到,访问地址是localhost,端口是80。

  1. $ curl localhost/myapp/
  2. {"code":0,"data":"hello world","message":"success"}
  3. $ curl localhost/myapp/ping
  4. {"code":0,"data":"pong","message":"success"}
  5. $ curl localhost/myapp/hello
  6. {"code":0,"data":"world","message":"success"}

参考

https://start.aliyun.com/handson-lab