如何轻松构建适用于 K8S 的 CI/CD 管道?
技术
作者:Sergey Ryabin
译者:小君君
2019-04-30 09:35

Concourse CI 是一款 CI/CD 工具,它可以用于驱动 Serverless 应用程序的部署和更新。

本文通过一组简单的示例,帮助开发者轻松理解如何使用 Concourse CI/CD 管道在 Kubernetes 上部署和更新 scale-to-zero REST API 服务。*如果你还不了解 Concourse CI,你可以先学习一下 Concourse 的原理。请参见 Concourse 官网[1]。 

如果一个开发团队有办法对应用程序进行持续集成(CI)和持续交付(CD),那么实现快速开发就不是一个难题。 


下文的教程将帮助开发者轻松构建完整的 CI/CD 管道,并自动将 Serverless 应用程序投入到生产中:git 提交——构建——测试——发布组件——在 Kubernetes/Knative 上部署和更新应用程序。通过本文你将了解到:

  • 安装 Knative;
  • 构建 REST API 应用程序示例;
  • 通过 CI/CD 管道部署 Serverless 应用程序;
  • 验证 Serverless 应用程序;
  • 通过 CI/CD 管道更新 Serverless 应用程序。

安装 Knative 

首先,在 Kubernetes 集群中安装 Knative 中间件。这里我们将举例说明如何在 GKE 上进行设置,各位读者也可以参考官方安装指南[2]进行操作。Knative 需要将请求路由到 Knative 服务的入口网关,所以我们先安装它:

$ kubectl apply -f https://github.com/knative/serving/releases/download/v0.4.0/istio-crds.yaml
$ kubectl apply -f https://github.com/knative/serving/releases/download/v0.4.0/istio.yaml
$ kubectl label namespace default istio-injection=enabled

等待 Istio 安装完毕:

$ watch kubectl -n istio-system get pods

安装 Knative 组件:

$ kubectl apply -f
https://github.com/knative/serving/releases/download/v0.4.0/serving.yaml -f
https://github.com/knative/build/releases/download/v0.4.0/build.yaml -f
https://github.com/knative/eventing/releases/download/v0.4.0/release.yaml -f
https://github.com/knative/eventing-sources/releases/download/v0.4.0/release.yaml -f
https://github.com/knative/serving/releases/download/v0.4.0/monitoring.yaml -f
https://raw.githubusercontent.com/knative/serving/v0.4.0/third_party/config/build/clusterrole.yaml

等待所有 knative-components 准备就绪:

$ kubectl get pods -n knative-monitoring
$ kubectl get pods -n knative-build
$ kubectl get pods -n knative-
eventing $ kubectl get pods -n knative-source
$ kubectl get pods -n knative-serving

构建 REST API 应用程序示例 

 第二步,使用 Knative 存储库中的 Golang 应用程序示例:

$ export GOPATH=`pwd`
$ go get -d github.com/knative/docs/docs/serving/samples/rest-api-go
$ cd $GOPATH/src/github.com/Aptomi/knative-docs
$ export REPO=<DOCKER_HUB_ACCOUNT>/rest-api
$ docker build --tag "${REPO}"  --file docs/serving/samples/rest-api-go/Dockerfile .

构建一个 REST API 应用程序:

Sending build context to Docker daemon  59.89MB
Step 1/8 : FROM golang AS builder
---> 36e5881731e4
Step 2/8 : WORKDIR /go/src/github.com/knative/docs/
---> Using cache
---> 2284037457d4
Step 3/8 : ADD . /go/src/github.com/knative/docs/
---> 535fc84bcba5
Step 4/8 : RUN CGO_ENABLED=0 go build ./docs/serving/samples/rest-api-go/
---> Running in 7215a7bcdbcf
Removing intermediate container 7215a7bcdbcf
---> 59acd91aecdf
Step 5/8 : FROM gcr.io/distroless/base
latest: Pulling from distroless/base
41d633039bbf: Pull complete
5f5edd681dcb: Pull complete
Digest: sha256:a9bc1c4720b17441d5fb95937a66616a9ae96339599e3959ae2f5db71e7e089e
Status: Downloaded newer image for gcr.io/distroless/base:latest
---> a5a1c6b2c22f
Step 6/8 : EXPOSE 8080                                                                                                                            
---> Running in c2d6fcdd6098
Removing intermediate container c2d6fcdd6098
---> 45cc32b2e3a6
Step 7/8 : COPY --from=builder /go/src/github.com/knative/docs/rest-api-go /sample
---> c06fa51dcd1f
Step 8/8 : ENTRYPOINT ["/sample"]
---> Running in cd2559eb09fe
Removing intermediate container cd2559eb09fe
---> b5f712672524
Successfully built b5f712672524
Successfully tagged <DOCKERHUB_ACCOUNT>/rest-api:latest

并将其推送到 Docker 存储库中:

$ docker push ${REPO}
The push refers to repository [docker.io/<DOCKERHUB_ACCOUNT>/rest-api]
33ab4bae26dc: Pushed
883ad731c7dd: Pushed
e9c843895906: Pushed
latest: digest: sha256:83272c0f1117abbbfa8a7f95aa8ebbcadc506e9ca70cb3022ed41755687011c8

通过 CI/CD 管道部署 Serverless 应用程序 

 第三步,构建一个 Concourse CI/CD 管道,将这个 REST API 应用程序以“Serverless”模式部署到 Kubernetes 中。 


该管道会检查 Docker Hub 上的新应用程序镜像,并在镜像更新时将 REST API 应用程序部署到 Kubernetes/Knative 中。

jobs:
 - name: rest-api
   plan:
     - get: docker-image
       trigger: true
     - put: knative-serving
       params:
         kubectl: cluster-info
         app_name: rest-api
         image: ((docker_repo))
         namespace: default
resource_types:
 - name: knative-serving
   source:
     repository: aptomisvc/concourse-knative-serving-resource
     tag: latest
   type: docker-image

resources:
 - name: knative-serving
   type: knative-serving
   source:
     kubeconfig: ((kubeconfig))
 - name: docker-image
   type: docker-image
   source:
     repository: ((docker_repo))
     tag: latest

这里我们用了由 Aptomi 编写的自定义 Concourse 资源,它允许从 Concourse 管道将应用程序部署到 Knative 中:

  • https://github.com/Aptomi/concourse-knative-serving-resource

只需要三个参数:应用程序的名称、Docker 镜像和部署应用程序的 Kubernetes 命名空间。
你可以从我们的存储库下载管道并将其导入 Concourse 中: 

 

$ curl -LO https://raw.githubusercontent.com/Aptomi/concourse-pipelines/master/knative-serving/01_knative_serving_pipeline.yml

$ fly -t concourse set-pipeline -p knative-serving-example -c ./01_knative_serving_pipeline.yml --var "kubeconfig=$(cat kubeconfig)" --var docker_repo="${REPO}"

$ fly -t concourse unpause-pipeline -p knative-serving-example

之后,管道将自动由 docker-image 资源触发: 



 并开始部署应用程序: 

现在,检查一下应用程序是否已真正部署到 Knative 中:

$ kubectl -n default get ksvc
NAME DOMAIN LATESTCREATED LATESTREADY READY REASON
rest-api rest-api.default.example.com rest-api-00001 rest-api-00001

这里我们的 REST API 服务可以登陆到 rest-api.default.example.com 域中。你可以检查服务、路由和部署等其他对象: 

验证 Serverless 应用程序

现在,你可以通过 Kubernetes Ingress 向部署的 REST API 发出一个简单的请求。从 Knative v0.4.0 开始,Knative 可以使用 istio-ingress 网关来处理网络请求。

$ INGRESSGATEWAY=istio-ingressgateway
$ INGRESSGATEWAY_LABEL=istio
$ export INGRESS_IP=`kubectl get svc
$INGRESSGATEWAY --namespace istio-system --output jsonpath="{.status.loadBalancer.ingress[*].ip}"`
$ export SERVICE_HOSTNAME=`kubectl get ksvc rest-api --output jsonpath="{.status.domain}"`

在这个例子里,外部 IP 地址是 35.188.208.253,主机名是 rest-api.default.example.com。现在,你可以发出第一个 HTTP 请求:

$ time curl --header "Host:$SERVICE_HOSTNAME" http://${INGRESS_IP}
Welcome to the stock app!

real    0m8,122s
user    0m0,008s
sys     0m0,023s

如你所见,第一个请求处理了大约 8 秒。因为 Knative 的一个功能是自动放大或缩小到零,所以在这种特殊情况下,你会收到了一个新的 HTTP 请求,但是应用程序 Pod 不会运行。同时,Knative 会花一些时间来启动一个应用程序,并为刚刚发出的第一个请求提供服务。

$ kubectl get pods -l app=rest-api-00001NAME                                        READY   STATUS    RESTARTS   AGE

检查 Pod:

$ kubectl get pods -l app=rest-api-00001NAME                                        READY   STATUS    RESTARTS   AGE
rest-api-00001-deployment-99c8c558d-45fs8 3/3  Running 0 1m

发送另一个 HTTP 请求,查看所需时间:

$ time curl --header "Host:$SERVICE_HOSTNAME" http://${INGRESS_IP}
Welcome to the stock app!

real    0m0,350s
user    0m0,024s
sys     0m0,014s

该请求耗时 0.35 秒,因为该 Pod 已经运行并可立即为请求提供服务。如果应用程序在一段时间内不会收到其他 HTTP 请求,Knative 会将其缩小为零并终止相应的 Pod。

通过 CI/CD 管道更新 Serverless 应用程序 

最后,我们可以在应用程序中进行一些更改,比如在 docs/serving/samples/rest-api-go/stock.go 文件中更改带有 banner 消息的行。 

重建 Docker 镜像并将它推送到 repo 中:

$ docker build --tag "${REPO}" --file docs/serving/samples/rest-api-go/Dockerfile .
$ docker push ${REPO}
The push refers to repository [docker.io/aptomi/rest-api]
883ad731c7dd: Layer already exists
e9c843895906: Layer already exists
34aCxabe27yy: Pushed
latest: digest: sha256:2414c0faa47abxyfa8a7b95aa8ebbcadd440e9ca70cb2311ed4175514h01aa8 size: 949

Concourse 资源将自动发现它并触发相同的 CI/CD 管道,将应用程序重新部署到 Knative 上:
 


通过 Concourse CI/CD 管道检查应用程序是否已更新:

$ curl --header "Host:$SERVICE_HOSTNAME" http://${INGRESS_IP}
Welcome to the stock v2 app!

以上就是本次教程的全部内容,你如何看待利用 Concourse CI/CD 部署 scale-to-zero REST API 服务?如果感兴趣,不妨在读完本文后,亲自动手进行尝试。

--参考文献:

1.https://concourse-ci.org/?spm=a2c63.p38356.879954.7.229155b1B8fT382.https://www.huodongxing.com/event/7486521953311



 

161 comCount 0