kubesphere生产环境落地实践(三)镜像管理

Posted

tags:

篇首语:本文由小常识网(cha138.com)小编为大家整理,主要介绍了kubesphere生产环境落地实践(三)镜像管理相关的知识,希望对你有一定的参考价值。

参考技术A 镜像管理部分,我们分以下三个章节进行讨论:

这里举个我们后台应用镜像构建的例子,来论述整个流程

方便起见,我们将该应用命名 应用A ,并且 应用A 为 java 应用。

应用A 的构建流程主要分为以下几个部分:

整个流程我们以 gitlab-runner 作为 CI 工具串联(因为足够简单), gitlab-ci 配置如下

需要说明的是,我们以 $CI_COMMIT_SHORT_SHA (gitlab commit id)作为镜像的 tag ,保证每次构建镜像tag的唯一性。

由于每次触发构建后,都将生成新的镜像并推送至私有镜像库harbor中,随着时间的推移,镜像库内的镜像呈线性堆积,所以对于私有镜像库内镜像的清理工作尤为重要。(尽管基础镜像层级可以复用,但镜像占用的存储空间依然很大,主要与jar包大小有直接关系)

对于镜像的清理,我们使用habror原生的GC功能,具体配置如下:

通过以上两条配置,基本满足我们对镜像清理的需求

这里所说的镜像迁移,指的是实际投产时,需要将镜像发布至现场(第一次全量)。实际就是将所需镜像导出,传输至现场,导入现场私有库内。

开始阶段我们使用原生docker进行镜像的导出,整个流程如下:

在实操过程中,我们发现docker批量对镜像导出的效率是及其低的。对几百个镜像拉取、导出、压缩的操作耗时往往为小时级别。

后续我们参考了 镜像搬运工具 Skopeo 使用 - 云+社区 - 腾讯云 (tencent.com) 这篇文章,选用skopeo替代docker作为镜像导出、导入工具。效果显著,耗时降为分钟级。

以下为我们使用skopeo导出镜像的样例

sync.sh

load.sh

harbor.yml

值得说明的是,我们使用 easyctl 从harbor库中导出镜像tag列表(按repo导出)

镜像tag列表如下:

images/images-list.txt

以上内容就是我们在使用kubepshere过程中,对于镜像制品的管理。

Istio流量管理实践之: 基于Istio实现流量对比分析

流量镜像
流量镜像,也称为影子流量,流量镜像提供一种尽可能低的风险为生产带来变化的强大功能。镜像会将实时流量的副本发送到镜像服务。镜像流量发生在主服务的关键请求路径之外。

在非生产或者测试环境中,尝试访问一个服务所有可能的测试用例组合是个非常不现实的任务。 在某些情况下,编写这些用例的所有工作也可能与实际生产所需的用例不匹配。在理想情况下,可以使用实时的生产用例和流量来帮助完善在测试环境中错过的功能区域。

一旦我们能够可靠地镜像流量,就可以开始做一些有价值的事情,例如通过请求流量对比工具Diffy,可以将引入测试集群的流量与生产集群中的预期行为进行比较。例如,我们可能想比较请求结果与预期结果间的偏差,或是API协议中的数据损坏情况,以便更好地兼容。
除此之外,需要注意:

当流量镜像到不同的服务时,会发生在请求的关键路径之外;
忽略对任何镜像流量的响应; 流量被视为“即发即忘”;
流量对比
此处,插入一个代理就可以负责此类流量的协调,并对其进行有趣的比较。Diffy就是一款这样的代理工具。Diffy启动一个代理服务(例如监听端口8880),再根据用户设置的primary、secondary两个旧服务地址(primary和secondary代码完全相同,目的是为了减少噪音干扰)、candidate新服务地址。

它还能够检测结果中的噪音,并通过先调用两个实时服务的实例来忽略它们(例如时间戳,单调递增计数器等提示),总结来说就是检测,然后在测试服务中忽略掉这部分。

技术分享图片

Diffy还提供了一个不错的页面可以用来查看调用结果、对比情况、和基于某些特征的过滤。它还有一个很好的管理控制台,可以查看有关调用比较结果的功能指标(metrics)和统计数据(statistics)。

创建用于Istio流量镜像的服务
在此任务中,将首先强制所有流量到 v1 版本的服务。然后,将使用规则将一部分流量镜像到 v2版本。

首先部署两个版本的示例服务。

版本1的部署使用了Docker镜像httpbin,提供常见的http请求访问:

apiVersion: extensions/v1beta1
kind: Deployment
metadata:
name: mirrorservice-sample-v1
spec:
replicas: 1
template:
metadata:
labels:
app: mirrorservice-sample
version: v1
spec:
containers:

  • image: docker.io/kennethreitz/httpbin
    imagePullPolicy: IfNotPresent
    name: mirrorservice-sample
    command: ["gunicorn", "--access-logfile", "-", "-b", "0.0.0.0:44134", "httpbin:app"]
    ports:
    • containerPort: 44134
      版本2的部署使用了自定义的Docker镜像,对应的Dockerfile如下:

FROM nginx:latest
COPY default.conf /etc/nginx/conf.d/
EXPOSE 80
所需的nginx 配置文件:

server {
listen 44134;
server_name localhost;

location / {
    proxy_pass http://httpbin-diffy.diffy:8880/;
    proxy_http_version 1.1;
    proxy_set_header Upgrade $http_upgrade;
    proxy_set_header Connection "upgrade";   
}

}
版本2的部署作为Istio的流量镜像目标,在接收到流量之后会转发到Diffy的代理中。当前没有直接将Diffy代理作为Isito流量镜像目标,原因是Diffy代理与Envoy代理目前本身有冲突,无法正常流量转发,因此需要此部署中转一下。

apiVersion: extensions/v1beta1
kind: Deployment
metadata:
name: mirrorservice-sample-v2
spec:
replicas: 1
template:
metadata:
labels:
app: mirrorservice-sample
version: v2
spec:
containers:

  • name: mirrorservice-sample
    image: registry.cn-beijing.aliyuncs.com/wangxining/mirrorservice:0.1
    imagePullPolicy: Always
    ports:
    • containerPort: 44134
      对应的Kubernetes service:

apiVersion: v1
kind: Service
metadata:
name: mirrorservice-sample
spec:
type: ClusterIP
ports:

  • name: http
    port: 44134
    selector:
    app: mirrorservice-sample
    创建流量镜像的Istio策略
    默认情况下,Kubernetes 在服务的两个版本之间进行负载均衡。创建如下流量镜像规则将 100% 的流量发送到 v1, 同时指定流量镜像到v2。当流量被镜像时,请求将通过其主机/授权报头发送到镜像服务附上 -shadow 。

apiVersion: networking.istio.io/v1alpha3
kind: DestinationRule
metadata:
name: mirrorservice-sample
spec:
host: mirrorservice-sample
subsets:

  • name: v1
    labels:
    version: v1
  • name: v2
    labels:
    version: v2

    apiVersion: networking.istio.io/v1alpha3
    kind: VirtualService
    metadata:
    name: mirrorservice-sample
    spec:
    hosts:

    • mirrorservice-sample
      http:
  • route:
    • destination:
      host: mirrorservice-sample
      subset: v1
      weight: 100
      #- destination:

      host: mirrorservice-sample

      subset: v2

      weight: 0

      mirror:
      host: mirrorservice-sample
      subset: v2
      搭建Diffy用于请求流量对比
      Diffy可以作为代理,截取请求并发送至所有运行的服务实例,通过对比响应结果来发现每次迭代代码中可能存在的问题。其中,Diffy上运行了三类代码实例:

线上稳定版本:一个运行线上稳定版本代码的节点
线上稳定版本备份:同样运行了线上的稳定版本,用于消除噪音
测试版本:待上线的测试版本,用于和线上环境代码进行对比
技术分享图片
在实际Diffy测试中,会发现大部分的接口都会有一定差异,原因是这些响应中存在了噪音,噪音可能包括:

server响应中生成的时间戳
随机生成的数字
系统服务间的有条件竞争
Diffy能够通过一定的方式,清除这类噪音,保证分析结果不被影响。

创建Diffy及示例服务
通过以下YAML创建Diffy服务:

apiVersion: v1
kind: Service
metadata:
name: httpbin-diffy
labels:
app: httpbin-diffy
spec:
ports:

  • name: http-proxy
    port: 8880
  • name: http-admin
    port: 8881
  • name: http-console
    port: 8888
    selector:
    app: httpbin-diffy

    apiVersion: extensions/v1beta1
    kind: Deployment
    metadata:
    labels:
    app: httpbin-diffy
    version: v2
    name: httpbin-diffy-v2
    spec:
    replicas: 1
    selector:
    matchLabels:
    app: httpbin-diffy
    version: v2
    template:
    metadata:
    labels:
    app: httpbin-diffy
    version: v2
    spec:
    containers:

    • image: lordofthejars/diffy:1.0
      imagePullPolicy: IfNotPresent
      livenessProbe:
      exec:
      command:
      • curl
      • localhost:8888
        initialDelaySeconds: 10
        periodSeconds: 60
        timeoutSeconds: 1
        name: httpbin-diffy
        args: ["-candidate=httpbin-candidate:8080", "-master.primary=httpbin-master:8080", "-master.secondary=httpbin-master:8080", "-service.protocol=http", "-serviceName=httpbin", "-proxy.port=:8880", "-admin.port=:8881", "-http.port=:8888", "-rootUrl=‘localhost:8888‘"]
        ports:
        • containerPort: 8888
          name: http-console
          protocol: TCP
        • containerPort: 8880
          name: http-proxy
          protocol: TCP
        • containerPort: 8881
          name: http-admin
          protocol: TCP
          readinessProbe:
          exec:
          command:
      • curl
      • localhost:8888
        initialDelaySeconds: 10
        periodSeconds: 60
        timeoutSeconds: 1
        securityContext:
        privileged: false
        通过以下YAML创建示例所用的primary、secondary(当前示例中与primary相同)与candidate服务:

apiVersion: v1
kind: Service
metadata:
name: httpbin-master
labels:
app: httpbin-master
spec:
ports:

  • name: http
    port: 8080
    selector:
    app: httpbin
    version: v1

    apiVersion: v1
    kind: Service
    metadata:
    name: httpbin-candidate
    labels:
    app: httpbin-candidate
    spec:
    ports:

  • name: http
    port: 8080
    selector:
    app: httpbin
    version: v2

    apiVersion: extensions/v1beta1
    kind: Deployment
    metadata:
    name: httpbin-v1
    spec:
    replicas: 1
    template:
    metadata:
    labels:
    app: httpbin
    version: v1
    spec:
    containers:

    • image: docker.io/kennethreitz/httpbin
      imagePullPolicy: IfNotPresent
      name: httpbin
      command: ["gunicorn", "--access-logfile", "-", "-b", "0.0.0.0:8080", "httpbin:app"]
      ports:
      • containerPort: 8080

        apiVersion: extensions/v1beta1
        kind: Deployment
        metadata:
        name: httpbin-v2
        spec:
        replicas: 1
        template:
        metadata:
        labels:
        app: httpbin
        version: v2
        spec:
        containers:

    • image: docker.io/kennethreitz/httpbin
      imagePullPolicy: IfNotPresent
      name: httpbin
      command: ["gunicorn", "--access-logfile", "-", "-b", "0.0.0.0:8080", "httpbin:app"]
      ports:
      • containerPort: 8080
        发送流量进行镜像验证
        启动 sleep 服务,这样就可以使用 curl 来提供负载:

cat <<EOF | istioctl kube-inject -f - | kubectl create -f -
apiVersion: extensions/v1beta1
kind: Deployment
metadata:
name: sleep
spec:
replicas: 1
template:
metadata:
labels:
app: sleep
spec:
containers:

  • name: sleep
    image: tutum/curl
    command: ["/bin/sleep","infinity"]
    imagePullPolicy: IfNotPresent
    EOF
    进入到SLEEP_POD, 具体POD名称根据实际赋值。

kubectl exec -it $SLEEP_POD -c sleep sh
发送流量:

curl -v http://mirrorservice-sample:44134/headers
可以查看 v1的访问日志记录,如下所示创建的请求100%指向了v1。
技术分享图片

与此同时,查看Diffy的Web界面,可以看到创建的请求也被镜像到Diffy Proxy:
技术分享图片
技术分享图片

Diffy能够通过一定的方式,清除这类噪音,保证分析结果不被影响。
技术分享图片

结论
流量镜像提供一种尽可能低的风险为生产带来变化的强大功能。镜像会将实时流量的副本发送到镜像服务,镜像流量发生在主服务的关键请求路径之外。一旦我们能够可靠地镜像流量,就可以开始做一些有价值的事情,例如通过请求流量对比工具Diffy,可以将引入测试集群的流量与生产集群中的预期行为进行比较。

支持流量镜像只是 Istio 的众多功能之一,它将使基于大型微服务的应用程序的生产部署与管理变得更加简单。欢迎大家使用阿里云上的容器服务,快速搭建微服务的开放治理平台Istio,比较简单地集成到自己项目的微服务开发中。

以上是关于kubesphere生产环境落地实践(三)镜像管理的主要内容,如果未能解决你的问题,请参考以下文章

Istio流量管理实践之: 基于Istio实现流量对比分析

Istio流量管理实践之: 基于Istio实现流量对比分析

生产环境容器落地最佳实践 -JFrog 内部K8s落地旅程

设计模式: 实际场景的落地应用(含开源项目和生产环境实践)--持续更新中

Jenkins和Docker在HULK的落地实践

基于 KubeSphere 流水线的 GitOps 最佳实践