Donald

Donald 查看完整档案

填写现居城市  |  填写毕业院校  |  填写所在公司/组织填写个人主网站
编辑

布道者,Linux基金会(LFAPAC)
开发者布道者,云原生计算基金会(CNCF)

个人动态

Donald 发布了文章 · 2月2日

在Kubernetes上部署OpenTelemetry收集器

10人将获赠CNCF商店$100美元礼券!

你填了吗?

image

问卷链接(https://www.wjx.cn/jq/9714648...


作者:Juraci Paixão Kröhling

OpenTelemetry 收集器是一个二进制程序,通常作为代理部署在运行业务应用程序的主机上,但是现在越来越多的应用程序运行在像 Kubernetes 这样的容器平台上。

在 Kubernetes 上运行 OpenTelemetry 收集器需要什么呢?

OpenTelemetry 收集器项目附带了一个示例文件以供 Kubernetes 使用,但是该示例文件的目的是作为一个指南,而不是作为一个可用于生产的解决方案。收集器是如此通用,以至于几乎不可能实现一刀切的部署配置。

部署模式

收集器的裸金属部署很容易规划和执行:它是作为主机上的守护进程运行的单个二进制文件。然而,对于 Kubernetes,我们有几个选择:

  • Deployment,多个副本可能在同一个节点上共存
  • DaemonSet,每个 Kubernetes 节点都有一个实例
  • StatefulSet,始终存在精确数量的副本,每个副本都有一个可预测的名称(collector-1, collector-2,…)
  • Sidecar,一个实例作为容器与运行你的业务应用程序的每个 pod 一起存在,扮演代理的角色

最常见的情况是,你可以混合使用 Deployment 和 Sidecar:Deployment 具有高度弹性,可以通过水平 Pod Autoscale 自动伸缩,而 Sidecar 允许你的应用程序将遥测数据卸载到运行在同一“主机”中的进程。Sidecar 更有可能拥有特定于业务应用程序的定制配置(即处理器),而 Deployment 通常是更通用的配置。

DaemonSet 最常用于单租户、多云部署,在这种情况下,需要确保来自应用程序的遥测数据在到达公共 internet 之前由同一个节点中的一个进程进行预处理。

当收集器实例的副本数量不会频繁更改,并且你正在使用可以从稳定的主机名列表(例如负载平衡导出器)中受益的处理器时,应该使用 StatefulSet。

开列清单

为部署设计好拓扑之后,就可以开始编制清单了!对于本例,我们将使用经典的 Deployment+Sidecar 模式。

无论采用哪种部署模式,你都可能需要为收集器提供一个配置文件。因为这必须是一个实际的文件,我们将为它创建一个 ConfigMap,像这样:

---
apiVersion: v1
kind: ConfigMap
metadata:
  name: collector-config
data:
  collector.yaml: |
    receivers:
      otlp:
        protocols:
          grpc:
    processors:
    exporters:
      logging:
    service:
      pipelines:
        traces:
          receivers: [otlp]
          processors: []
          exporters: [logging]
---
apiVersion: v1
kind: ConfigMap
metadata:
  name: agent-config
data:
  agent.yaml: |
    receivers:
      otlp:
        protocols:
          grpc:
    processors:
    exporters:
      otlp:
        endpoint: "opentelemetrycollector.default.svc.cluster.local:4317"
        insecure: true
    service:
      pipelines:
        traces:
          receivers: [otlp]
          processors: []
          exporters: [otlp]

接下来,我们可以创建我们的 Deployment。最简单的解决方案是:

apiVersion: apps/v1
kind: Deployment
metadata:
  name: opentelemetrycollector
spec:
  replicas: 1
  selector:
    matchLabels:
      app.kubernetes.io/name: opentelemetrycollector
  template:
    metadata:
      labels:
        app.kubernetes.io/name: opentelemetrycollector
    spec:
      containers:
      - name: otelcol
        args:
        - --config=/conf/collector.yaml
        image: otel/opentelemetry-collector:0.18.0
        volumeMounts:
        - mountPath: /conf
          name: collector-config
      volumes:
      - configMap:
          items:
          - key: collector.yaml
            path: collector.yaml
          name: collector-config
        name: collector-config

我们现在有了一个启动并运行的收集器实例,但是它仍然不能接收数据:为此,我们需要一个Service来暴露我们在配置中声明的 OTLP 端口。以下是满足该需求的服务定义:

apiVersion: v1
kind: Service
metadata:
  name: opentelemetrycollector
spec:
  ports:
  - name: grpc-otlp
    port: 4317
    protocol: TCP
    targetPort: 4317
  selector:
    app.kubernetes.io/name: opentelemetrycollector
  type: ClusterIP

测试

现在,我们已经为收集器准备好了所有部件,现在是时候启动一个生成跟踪并将其发送到收集器的应用程序了。为此,我们将创建一个 Deployment,其中包含一个应用程序,该应用程序为接收到的每个 HTTP 请求创建跟踪。这个应用程序被打包在一个名为quay.io/jpkroehling/generate-span-java:0.1.0的容器镜像中,我们可以使用如下 Deployment:

apiVersion: apps/v1
kind: Deployment
metadata:
  name: myapp
spec:
  replicas: 1
  selector:
    matchLabels:
      app.kubernetes.io/name: myapp
  template:
    metadata:
      labels:
        app.kubernetes.io/name: myapp
    spec:
      containers:
      - name: myapp
        image: quay.io/jpkroehling/generate-span-java:0.1.0
      - name: agent
        image: otel/opentelemetry-collector:0.18.0
        args:
        - --config=/conf/agent.yaml
        volumeMounts:
        - mountPath: /conf
          name: agent-config
      volumes:
      - configMap:
          items:
          - key: agent.yaml
            path: agent.yaml
          name: agent-config
        name: agent-config

当 Deployment 就绪,我们就可以调用它的/orders 端点,它将为我们生成一些跨度。进行测试的最简单方法是执行端口转发,这样对 localhost:8080/orders 的调用就会落在 Kubernetes 集群中的应用程序上:

$ kubectl port-forward deployment/myapp 8080
Forwarding from 127.0.0.1:8080 -> 8080

现在让我们为我们的收集器跟踪日志:一旦我们调用了我们的服务,收集器中的 loggingexport 将确保在日志中记录这个事件。

$ kubectl logs deployments/opentelemetrycollector -f
...
2021-01-22T12:59:53.561Z info service/service.go:267 Everything is ready. Begin running and processing data.

最后,让我们生成一些跨度:

$ curl localhost:8080/order
Created

在收集器的日志中,我们现在应该看到如下内容:

2021-01-22T13:26:49.320Z INFO loggingexporter/logging_exporter.go:313 TracesExporter {"#spans": 2}
2021-01-22T13:26:49.430Z INFO loggingexporter/logging_exporter.go:313 TracesExporter {"#spans": 1}
2021-01-22T13:26:50.422Z INFO loggingexporter/logging_exporter.go:313 TracesExporter {"#spans": 4}
2021-01-22T13:26:50.571Z INFO loggingexporter/logging_exporter.go:313 TracesExporter {"#spans": 1}

这证实了在我们的应用程序中生成的跨已经通过 sidecar 代理转到收集器。在真实的设置中,我们将配置收集器以将我们的 span 导出到真实的后端,如 Jaeger 或 Zipkin。

其他选择

到目前为止,你可能已经意识到在 Kubernetes 上部署一个简单的 OpenTelemetry 收集器实例并不是那么困难。但第二天的问题该怎样,比如版本升级?或者如何使 Service 与 ConfigMap 保持同步,以便配置中定义的所有端口都通过服务自动暴露?自动将 sidecar 注入到业务部署中不是很好吗?这些都是OpenTelemetry Operator 可以完成的任务。

如果你更喜欢 Helm Charts,也有一个实验性的版本可以安装收集器。

总结

OpenTelemetry 收集器是一个非常灵活和轻量级的进程,使混合和匹配策略成为可能,允许根据你非常特定的需求构建收集器链。在 Kubernetes 中部署收集器的单个实例并不是一项复杂的任务,尽管维护这些实例可能会让你考虑使用像 Helm Charts 或 Operator 这样的工具。

感谢 Gary Brown。

点击阅读网站原文


CNCF (Cloud Native Computing Foundation)成立于2015年12月,隶属于Linux  Foundation,是非营利性组织。
CNCF(云原生计算基金会)致力于培育和维护一个厂商中立的开源生态系统,来推广云原生技术。我们通过将最前沿的模式民主化,让这些创新为大众所用。扫描二维码关注CNCF微信公众号。
image

查看原文

赞 0 收藏 0 评论 0

Donald 发布了文章 · 1月27日

使用Python编写和提交Argo工作流

10人将获赠CNCF商店$100美元礼券!

你填了吗?

image

问卷链接(https://www.wjx.cn/jq/9714648...


作者:Alex Collins

Python 是用户在 Kubernetes 上编写机器学习工作流的流行编程语言。

开箱即用时,Argo 并没有为 Python 提供一流的支持。相反,我们提供Java、Golang 和 Python API 客户端

但这对大多数用户来说还不够。许多用户需要一个抽象层来添加组件和特定于用例的特性。

今天你有两个选择。

KFP 编译器+ Python 客户端

Argo 工作流被用作执行 Kubeflow 流水线的引擎。你可以定义一个 Kubeflow 流水线,并在 Python 中将其直接编译到 Argo 工作流中。

然后你可以使用Argo Python 客户端向 Argo 服务器 API 提交工作流。

这种方法允许你利用现有的 Kubeflow 组件。

安装:

pip3 install kfp
pip3 install argo-workflows

例子:

import kfp as kfp
def flip_coin():
    return kfp.dsl.ContainerOp(
        name='Flip a coin',
        image='python:alpine3.6',
        command=['python', '-c', """
import random
res = "heads" if random.randint(0, 1) == 0 else "tails"
with open('/output', 'w') as f:
    f.write(res)
        """],
        file_outputs={'output': '/output'}
    )
def heads():
    return kfp.dsl.ContainerOp(name='Heads', image="alpine:3.6", command=["sh", "-c", 'echo "it was heads"'])
def tails():
    return kfp.dsl.ContainerOp(name='Tails', image="alpine:3.6", command=["sh", "-c", 'echo "it was tails"'])
@kfp.dsl.pipeline(name='Coin-flip', description='Flip a coin')
def coin_flip_pipeline():
    flip = flip_coin()
    with kfp.dsl.Condition(flip.output == 'heads'):
        heads()
    with kfp.dsl.Condition(flip.output == 'tails'):
        tails()
def main():
    kfp.compiler.Compiler().compile(coin_flip_pipeline, __file__ + ".yaml")
if __name__ == '__main__':
    main()

运行这个来创建你的工作流:

apiVersion: argoproj.io/v1alpha1
kind: Workflow
metadata:
  generateName: coin-flip-
  annotations: {pipelines.kubeflow.org/kfp_sdk_version: 1.3.0, pipelines.kubeflow.org/pipeline_compilation_time: '2021-01-21T17:17:54.299235',
    pipelines.kubeflow.org/pipeline_spec: '{"description": "Flip a coin", "name":
      "Coin-flip"}'}
  labels: {pipelines.kubeflow.org/kfp_sdk_version: 1.3.0}
spec:
  entrypoint: coin-flip
  templates:
  - name: coin-flip
    dag:
      tasks:
      - name: condition-1
        template: condition-1
        when: '"{{tasks.flip-a-coin.outputs.parameters.flip-a-coin-output}}" == "heads"'
        dependencies: [flip-a-coin]
      - name: condition-2
        template: condition-2
        when: '"{{tasks.flip-a-coin.outputs.parameters.flip-a-coin-output}}" == "tails"'
        dependencies: [flip-a-coin]
      - {name: flip-a-coin, template: flip-a-coin}
  - name: condition-1
    dag:
      tasks:
      - {name: heads, template: heads}
  - name: condition-2
    dag:
      tasks:
      - {name: tails, template: tails}
  - name: flip-a-coin
    container:
      command:
      - python
      - -c
      - "\nimport random\nres = \"heads\" if random.randint(0, 1) == 0 else \"tails\"\
        \nwith open('/output', 'w') as f:\n    f.write(res)        \n        "
      image: python:alpine3.6
    outputs:
      parameters:
      - name: flip-a-coin-output
        valueFrom: {path: /output}
      artifacts:
      - {name: flip-a-coin-output, path: /output}
  - name: heads
    container:
      command: [sh, -c, echo "it was heads"]
      image: alpine:3.6
  - name: tails
    container:
      command: [sh, -c, echo "it was tails"]
      image: alpine:3.6
  arguments:
    parameters: []
  serviceAccountName: pipeline-runner

注意,Kubeflow 不支持这种方法。

你可以使用客户端提交上述工作流程如下:

import yaml
from argo.workflows.client import (ApiClient,
                                   WorkflowServiceApi,
                                   Configuration,
                                   V1alpha1WorkflowCreateRequest)
def main():
    config = Configuration(host="http://localhost:2746")
    client = ApiClient(configuration=config)
    service = WorkflowServiceApi(api_client=client)
with open("coin-flip.py.yaml") as f:
        manifest: dict = yaml.safe_load(f)
del manifest['spec']['serviceAccountName']
service.create_workflow('argo', V1alpha1WorkflowCreateRequest(workflow=manifest))
if __name__ == '__main__':
    main()

image

Couler

Couler是一个流行的项目,它允许你以一种平台无感的方式指定工作流,但它主要支持 Argo 工作流(计划在未来支持 Kubeflow 和 AirFlow):

安装:

pip3 install git+https://github.com/couler-proj/couler

例子:

import couler.argo as couler
from couler.argo_submitter import ArgoSubmitter
def random_code():
    import random
res = "heads" if random.randint(0, 1) == 0 else "tails"
    print(res)
def flip_coin():
    return couler.run_script(image="python:alpine3.6", source=random_code)
def heads():
    return couler.run_container(
        image="alpine:3.6", command=["sh", "-c", 'echo "it was heads"']
    )
def tails():
    return couler.run_container(
        image="alpine:3.6", command=["sh", "-c", 'echo "it was tails"']
    )
result = flip_coin()
couler.when(couler.equal(result, "heads"), lambda: heads())
couler.when(couler.equal(result, "tails"), lambda: tails())
submitter = ArgoSubmitter()
couler.run(submitter=submitter)

这会创建以下工作流程:

apiVersion: argoproj.io/v1alpha1
kind: Workflow
metadata:
  generateName: couler-example-
spec:
  templates:
    - name: couler-example
      steps:
        - - name: flip-coin-29
            template: flip-coin
        - - name: heads-31
            template: heads
            when: '{{steps.flip-coin-29.outputs.result}} == heads'
          - name: tails-32
            template: tails
            when: '{{steps.flip-coin-29.outputs.result}} == tails'
    - name: flip-coin
      script:
        name: ''
        image: 'python:alpine3.6'
        command:
          - python
        source: |
import random
res = "heads" if random.randint(0, 1) == 0 else "tails"
          print(res)
    - name: heads
      container:
        image: 'alpine:3.6'
        command:
          - sh
          - '-c'
          - echo "it was heads"
    - name: tails
      container:
        image: 'alpine:3.6'
        command:
          - sh
          - '-c'
          - echo "it was tails"
  entrypoint: couler-example
  ttlStrategy:
    secondsAfterCompletion: 600
  activeDeadlineSeconds: 300

image

点击阅读网站原文


CNCF (Cloud Native Computing Foundation)成立于2015年12月,隶属于Linux  Foundation,是非营利性组织。
CNCF(云原生计算基金会)致力于培育和维护一个厂商中立的开源生态系统,来推广云原生技术。我们通过将最前沿的模式民主化,让这些创新为大众所用。扫描二维码关注CNCF微信公众号。
image

查看原文

赞 0 收藏 0 评论 0

Donald 发布了文章 · 1月26日

Armada|如何使用Kubernetes在数千个计算节点上运行数百万个批处理作业

10人将获赠CNCF商店$100美元礼券!

你填了吗?

image

问卷链接(https://www.wjx.cn/jq/9714648...


客座文章作者:G-research 计算平台工程经理 Jamie Poole。博文最初在G-research 的博客上发表

在过去的几年中,我们已经将越来越多的工作负载迁移到 Linux 上的容器中。一种对我们来说非常重要的特殊类型的工作负载是运行到完成的批处理作业。我们的大部分业务使用大型计算网格来执行分布式数据科学和数值处理——在大型、嘈杂的真实世界数据集中寻找模式。直到最近,我们主要是使用运行在 Windows 上的HTCondor来实现这一点。

迁移到 Linux 和容器,我们有机会重新评估我们想要如何去做这件事。我们尝试在 Condor 和 Linux 上运行容器化作业,但在去了一遍巴塞罗那的 KubeCon,并与其他一些研究机构进行了交谈后,我们觉得使用 Kubernetes 可以做得更好。我们已经在 Kubernetes 上运行了许多服务,因此拥有一个具有 Kubernetes 所带来的所有操作和功能优势的逻辑计算平台是很有吸引力的。

很明显,原味的 Kubernetes 不能满足我们的用例。我们有一个大型的、固定的 on-prem 计算池,Condor 模型的优点之一是,你可以提交比你的基础设施一次处理的更多的作业,多余的作业在外部排队,并使用公平共享系统进行优先级排序。我们已经知道 Kubernetes 是容器编排的最佳品种,但在过度供应时,它缺乏对作业进行排队或公平调度的能力。如果我们能够启用这些额外的特性,我们是否能够将 Kubernetes 也用于批处理作业基础架构,并为所有计算提供一个单一的逻辑平台?

我们开始了一个内部实验,命名为 Armada。我们有一些关键的架构原则要遵守:

  • 编写一些软件来添加排队和公平共享,而不需要修改 Kubernetes 本身。让 Kubernetes 来做节点调度和容器生命周期管理的艰苦工作。
  • 支持多个集群,这样我们就可以超越单个 Kubernetes 集群的限制,并获得多个集群的操作优势。我们的目标是运行一个由数千台服务器组成的机队。
  • 使用基于拉的模型来获得工作,让我们更容易扩大规模

此外,我们从一开始就希望它是开源的。我们已经从开源技术中受益越来越多,尤其是 Kubernetes 本身。我们认为,如果我们能够生产出一些东西来解决我们的问题,那么它很可能会对其他人有用,这可能是一个很好的机会来回馈我们正在从中受益的生态系统。我们没有太多建立绿地开源项目的经验,所以简单地在 GitHub 上开始,以确保我们能够分享它。

我们很快就产生了一个概念验证,并有了一个应用程序,我们可以在 AWS 中使用它来证明 Kubernetes 能够在多个集群(每个集群有数百个节点)上运行数万个作业。重要的是,我们能够证明,只要我们在外部处理排队,Kubernetes 不需要进行任何特殊的调优,就可以处理数千个容器的启动和停止。

那么它是如何工作的呢?

image

Armada 的设计很简单。有一个中央服务器组件,用于存储要为不同用户或项目运行的作业队列。它负责维护整个系统的状态。它有一个 API,允许客户端以 Kubernetes pod 规范的形式提交作业,还可以监视作业的进度或取消作业。

在这下面,我们有一个 executor 组件,它可以部署到任何给定的 Kubernetes 集群中,允许检查集群并发现有多少资源(例如 CPU/GPU/内存)可用。它定期与服务器组件联系并租用要运行的作业,然后在本地创建 pod,将进度报告给服务器组件。作业完成后,将清理 pod,并为下一个作业提供空间。

缩放可以在二维水平进行。我们可以在专用的 executor 集群中增加节点,也可以根据需要增加更多的 executor 集群。由于使用基于拉的方法来租赁作业,我们可以轻松地添加或删除 executor 集群,而无需更改任何配置。

我们学到了什么?

根据我们的经验,我们已经验证了 Kubernetes 可以作为我们的计算场的计算基板的假设。它并不是完全一帆风顺的,在这个过程中我们遇到了一些有趣的边缘情况和问题。其中一些只是迁移到 Linux 和容器,不可避免地发现我们的代码在不知不觉中依赖于 Windows 操作系统及其生态系统。其他的是 Kubernetes 本身的问题,我们发现这些问题通常是由社区来解决的(例如:https://github.com/kubernetes/kubernetes/pull/90530——在使用静态 CPU 管理器时修复集群的过度分配)。这类事情本身就是一种验证——通过使用 Kubernetes,我们继承了所有社区的支持和项目的动力。

下一部

我们的环境正在增长,随着批处理工作负载迁移到 Linux,我们有了一个可靠的、可扩展的平台来运行它们。G-Research 中的 Kubernetes 是在 OpenStack 上提供的,我们可以重新提供现有的硬件,将其添加到 OpenStack 计算池中,以供 Kubernetes 使用。随着更多的工作负载迁移,看到环境的规模不断扩大是令人兴奋的。现在我们已经验证了平台的运行稳定性,我们想把重点放在可用性上。我们为用户设计了一个简单的 UI,使用户能够更容易地可视化他们的工作在系统中的流动,同时也使管理员更容易地从整体上理解系统。我们正在努力提高平台部署的自动化程度,尽可能让系统在部署后就可以“正常工作”。

我们欢迎你自己看看,尝试一下,并感谢任何反馈:https://github.com/G-Research/armada

如果你想加入我们的团队并与我们一起在很酷的项目工作,G-Research 在英国和我们的远程 GR 开源组总是在招聘有能力的开发者。

点击阅读网站原文


CNCF (Cloud Native Computing Foundation)成立于2015年12月,隶属于Linux  Foundation,是非营利性组织。
CNCF(云原生计算基金会)致力于培育和维护一个厂商中立的开源生态系统,来推广云原生技术。我们通过将最前沿的模式民主化,让这些创新为大众所用。扫描二维码关注CNCF微信公众号。
image

查看原文

赞 0 收藏 0 评论 0

Donald 发布了文章 · 1月22日

Artifact Hub 的容器镜像扫描和安全报告

2020年CNCF中国云原生调查

10人将获赠CNCF商店$100美元礼券!

你填了吗?

image

问卷链接(https://www.wjx.cn/jq/9714648...


作者:Matt Farina

当试图决定使用哪些制品时,了解一些关于制品安全性的信息是很有用的。使用Artifact Hub,可以看到基于容器的制品的安全扫描,比如基于 Operator Framework OLM 的操作器、一些 Helm Charts、OPA 策略和 Tinkerbell 操作。

OLM Operators

当一个操作器包含一个可以被扫描的镜像时,最后一次扫描的镜像,和访问完整的报告可以在侧边栏中找到。下图为Starboard Operator,由社区操作员提供,显示了一份没有漏洞的报告。

image

注意:SCRATCH 镜像,例如那些没有底层,只包含一个二进制文件的镜像,以及使用最新标记的镜像不会被扫描。

Helm Charts

Helm charts 的情况,就像基于 OLM 的操作器一样,可以选择进行镜像扫描和提供报告。下面的tavern chart 提供了一个示例,说明了一份没有漏洞的报告。与 OLM 操作器一样,它显示一个等级、执行最后一次扫描的时间以及查看完整报告的能力。

image

Helm charts 并不能提供一种简单的方法来获取所有可能在 chart 中使用的镜像。我们不可能知道如何在所有可能的配置中找到所有的图表来检测其中的镜像。为了使 Artifact Hub 能够发现镜像,chart 作者需要在 Chart.yaml 的注释中列出它们。格式示例如下:

annotations:
  artifacthub.io/images: |
    - name: img1
      image: repo/img1:1.0.0
    - name: img2
      image: repo/img2:2.0.0

你可以在Helm 支持的注释文档中了解更多关于列出镜像的信息。

它是如何工作的

安全报告是使用Trivy和定期扫描生成的。扫描仪检查未扫描的镜像。7 天前最后一次扫描的镜像会被重新扫描,即使没有更改包。这将使报告显示新发现的 CVE 的检测。

有些镜像无法被扫描,比如在一个 scratch 容器中使用二进制文件的镜像,或者使用 latest 标记的镜像。在这些情况下,将不显示报告。

你可以在文档中了解有关安全报告的更多信息。

点击阅读网站原文


CNCF (Cloud Native Computing Foundation)成立于2015年12月,隶属于Linux  Foundation,是非营利性组织。
CNCF(云原生计算基金会)致力于培育和维护一个厂商中立的开源生态系统,来推广云原生技术。我们通过将最前沿的模式民主化,让这些创新为大众所用。扫描二维码关注CNCF微信公众号。
image

查看原文

赞 0 收藏 0 评论 0

Donald 发布了文章 · 1月22日

Argo 的通知功能

2020年CNCF中国云原生调查

10人将获赠CNCF商店$100美元礼券!

你填了吗?

image

问卷链接(https://www.wjx.cn/jq/9714648...


作者:Alexander Matyushentsev

image

通知是完整的最终用户体验的重要组成部分,但却很难正确处理。不同的组织使用不同类型的通知服务,如 Slack、OpsGenie 或传统的电子邮件。可能需要通知的事件有几十种不同类型,因此很难预测所有可能的场景并对它们进行优化。最后,每个组织都有不同的标准,可能希望以不同的方式定制通知。

在过去的一年里,Argoproj 团队尝试了几种不同的通知方法。我们收到了很多反馈,也学到了很多东西,经过多次试验,我们很高兴正式宣布支持通知功能!我们已经设计并实现了一个可重用的 Golang 库,它可以满足各种 Argo 项目的通知功能需求。设计文档和库定义了配置语法、基本概念,并确保了所有 Argo 项目的一致用户体验。

Argo CD Notifications

Argo CD 是第一个提供通知的项目。Argo Rollouts 是下一个目标,之后 Argo Workflows 应该很快就能实现。在本文中,我们将学习一些基本概念,亲自动手,并使用 Argo CD 通知解决一些现实生活中的问题。

等等,Argo Rollouts 和 Workflows 呢?好消息是,所有 Argo 项目的通知设计和配置将非常相似,所以你今天学到的一切都将与所有 Argo 项目相关。

准备

首先,我们需要一个带有 Argo CD 的 Kubernetes 集群。如果你已经安装了带有 Argo CD 的集群,请放心进入下一步。如果没有,我们创建一个测试集群并安装 Argo CD。我们将使用以下指南:

如果你是一个 Mac 用户,那么指南可以归结为以下步骤。

  • 安装 minikube 和 Argo CD CLI:
brew install minikube argocd
  • 为这个演示创建一个新的 minikube 集群:
minikube start -p argocd-notifications-demo
  • 创建 argocd 命名空间并安装 argocd:
kubectl create namespace argocd
kubectl apply -n argocd -f https://raw.githubusercontent.com/argoproj/argo-cd/stable/manifests/install.yaml

完成了!现在我们有了一个带有 Argo CD 的 Kubernetes 集群,是时候安装和配置通知了!

基本通知

Argo CD Notifications 是一个可选的独立项目,应该安装在 argocd 命名空间中。让我们跟随这里提供的 Argo CD Notifications入门指南。安装过程包括:

kubectl apply -n argocd -f https://raw.githubusercontent.com/argoproj-labs/argocd-notifications/release-1.0/manifests/install.yaml
kubectl apply -n argocd -f https://raw.githubusercontent.com/argoproj-labs/argocd-notifications/release-1.0/catalog/install.yaml

第一个 YAML 文件安装负责通知处理的控制器,第二个配置的通知触发器和模板。我们将很快讨论触发器和模板,但首先,让我们配置与通知服务的集成。

通知服务集成

Argo CD 通知已经支持 Slack、电子邮件、Telegram、Netgenie、Grafana、定制 Webhooks,并且列表还在不断增长。你可以在Argo CD Notifications 文档中找到关于每个服务的详细说明。

image

为了简单起见,让我们配置普通的电子邮件集成,因为我们大多数人都使用电子邮件:

  • 存储你的电子邮件帐户用户名和密码到 argocd-notifications-secret 秘密:
export EMAIL_USER=<your-username>
export PASSWORD=<your-password>
kubectl apply -n argocd -f - << EOF
apiVersion: v1
kind: Secret
metadata:
  name: argocd-notifications-secret
stringData:
  email-username: $EMAIL_USER
  email-password: $PASSWORD
type: Opaque
EOF
注意:如果你正在使用 Gmail,那么你可以通过到https://myaccount.google.com/apppasswords创建一个应用程序密码,如下所述:https://support.google.com/accounts/answer/185833?hl=en
  • 电子邮件服务必须在 argocd-notifications-cm ConfigMap 中注册:
apiVersion: v1
kind: ConfigMap
metadata:
  name: argocd-notifications-cm
data:
  service.email.gmail: |
    username: $email-username
    password: $email-password
    host: smtp.gmail.com
    port: 465
    from: $email-username

要配置你的 Argo CD 实例,使用以下命令修补 ConfigMap:

kubectl patch cm argocd-notifications-cm -n argocd --type merge -p '{"data": {"service.email.gmail": "{ username: $email-username, password: $email-password, host: smtp.gmail.com, port: 465, from: $email-username }" }}'

完成了!现在,Argo CD 通知可以使用了。下一步是创建一个 Argo CD 应用程序并订阅通知。

订阅通知

Argo CD 通知订阅使用 notifications.argoproj.io/subscription 注释进行管理。继续,使用以下命令创建应用程序:

kubectl apply -n argocd -f - << EOF
apiVersion: argoproj.io/v1alpha1
kind: Application
metadata:
  name: guestbook
  annotations:
    notifications.argoproj.io/subscribe.on-sync-succeeded.gmail: $EMAIL_USER
spec:
  destination:
    namespace: default
    server: https://kubernetes.default.svc
  project: default
  source:
    path: kustomize-guestbook
    repoURL: https://github.com/argoproj/argocd-example-apps.git
    targetRevision: HEAD
  syncPolicy:
    automated: {}
EOF

当创建了应用程序,Argo CD 就会对应用程序清单进行协调和同步。是时候查看你的收件箱了!你应该会收到关于同步成功的电子邮件通知。

image

订阅、触发器和模板

现在是时候回过头来了解我们已经配置的详细内容了。让我们看看应用到 guestbook 应用程序的注释:

notifications.argoproj.io/subscribe.on-sync-succeeded.gmail: <email>

注释由以下部分组成:

  • notifications.argoproj.io/subscribe 是一个表示订阅的注释前缀
  • on-sync-succeeded 是捕获成功同步事件的触发器名称
  • gmail 是我们配置的基于电子邮件的服务的名称
  • <email>是需要通知的收件人电子邮件地址

除了 on-sync-succeeded 之外,其他一切都应该清楚。什么是触发器,为什么 on-sync-succeeded?

触发器定义了应该发送通知的条件。当需要发送通知时,它会连续地监视 Argo CD 应用程序的状态和需求。与通知服务一样,触发器在 argocd-notifications-cm 中配置。下面的 YAML 包含了 on-sync-succeeded 触发器配置:

apiVersion: v1
kind: ConfigMap
metadata:
  name: argocd-notifications-cm
data:
  trigger.on-sync-succeeded: |
    - when: app.status.operationState.phase in ['Succeeded']
      send: [app-sync-succeeded]

when 属性包含一个表达式,该表达式对应用程序进行计算并返回 true 或 false。

第二个有趣的属性是 send。它包含一个通知模板列表。该模板负责生成通知文本,并在 argocd-notifications-cm ConfigMap 中配置:

apiVersion: v1
kind: ConfigMap
metadata:
  name: argocd-notifications-cm
data:
  template.app-sync-succeeded: |
    message: |
      {{if eq .serviceType "slack"}}:white_check_mark:{{end}} Application {{.app.metadata.name}} has been successfully synced at {{.app.status.operationState.finishedAt}}.
Sync operation details are available at: {{.context.argocdUrl}}/applications/{{.app.metadata.name}}?operation=true .

如果你想利用更复杂的通知服务(如 Slack)的高级特性,那么模板可能会更复杂。

模板和触发器一起解决了两个重要的需求:为运营者提供强大的定制功能,同时为用户提供更好、更直观的用户体验。一方面,操作人员需要完全的灵活性和配置额外触发器和完全定制通知消息的能力,而最终用户只需要应用注释来订阅触发器和指定接收者。你可以在Argo CD 通知文档中了解更多关于触发器和模板的附加特性。

如果你一直认真地遵循这个练习,你可能已经注意到我们没有真正地配置 on-sync-succeeded 触发器和 app-sync-succeeded 模板。那么它们从何而来?我们从触发器和模板目录中获取了它们,这些目录包含了一系列有用的触发器和 Argo CD 模板。当我们使用以下命令配置 Argo CD Notifications 控制器时,目录已经安装好了:

kubectl apply -n argocd -f https://raw.githubusercontent.com/argoproj-labs/argocd-notifications/release-1.0/catalog/install.yaml

目录描述可以在 Argo CD Notifications 文档中找到,并在argoproj-labs/argocd-notifications仓库的 catalog 目录中定义。

接下来是?

通过 Argo Notifications,你可以做更多的事情。webhook 的集成是最令人兴奋的特性之一。webhook 支持有趣的用例,比如更好地与 Github 集成、触发 Jenkins jobs 等等。如果设置有任何问题,有一个 CLI 工具可以简化故障排除

如你所见,通知提供了一种与用户和其他服务交互的很好的方式!目前,通知功能只支持 Argo CD,但很快其他 Argo 项目也会支持。请敬请期待!

感谢 Ed Lee 和 Henrik Blixt。

点击阅读网站原文


CNCF (Cloud Native Computing Foundation)成立于2015年12月,隶属于Linux  Foundation,是非营利性组织。
CNCF(云原生计算基金会)致力于培育和维护一个厂商中立的开源生态系统,来推广云原生技术。我们通过将最前沿的模式民主化,让这些创新为大众所用。扫描二维码关注CNCF微信公众号。
image

查看原文

赞 0 收藏 0 评论 0

Donald 发布了文章 · 1月21日

迁移到Spark Operator和S3的4个集成步骤

2020年CNCF中国云原生调查

10人将获赠CNCF商店$100美元礼券!

你填了吗?

image

问卷链接(https://www.wjx.cn/jq/9714648...


客座文章作者:万事达卡首席软件开发工程师Allison Richardet

在万事达,内部云团队维护我们的Kubernetes平台。我们的工作包括维护Kubernetes集群,这是我们所依赖的核心部署,并为租户提供了日志、监控等服务,并为租户提供了良好的体验。

我们的租户之一,数据仓库团队,曾经在YARN和HDFS上使用过原生Apache Spark。他们找了我们的团队,希望将他们的大数据工作转移到Kubernetes;他们想要实现云原生化,而我们也有机会在Kubernetes上与Apache Spark合作。

所以,我们的旅程从Spark Operator开始。向Kubernetes和Operators的迁移将为我们的内部客户数据仓库团队打开云原生的可能性。我们有机会帮助他们利用可伸缩性和成本改进的优势,而切换到S3将进一步实现这些目标。

背景

操作器(operator)是什么,为什么我们,或者你,对此感兴趣?首先,操作器使用自定义资源扩展了Kubernetes API。操作器还定义了一个自定义控制器来监视其资源类型。将自定义资源与自定义控制器结合在一起会产生一个声明性API,在这个API中,操作器会协调集群声明状态与实际状态之间的差异。换句话说,操作器处理与其资源相关的自动化。

有了这些好处,我们的团队很高兴能够利用Kubernetes的Spark操作器来支持我们的租户。通常,原生Apache Spark使用HDFS。然而,迁移到云端并在Kuberentes上运行Spark操作器,S3是HDFS的一个很好的替代方案,因为它具有成本优势,并且能够根据需要进行扩展。有趣的是,S3在默认情况下不能与Spark操作器一起使用。我们参考了Spark操作器以及Hadoop-AWS集成文档。此外,我们将分享以下4个步骤的详细信息:镜像更新、SparkApplication配置、S3凭据和S3样式。遵循我们的步骤,将S3与你的Spark作业和Kubernetes的Spark操作器进行集成。

工作流程

与我们部署到Kubernetes集群的大多数应用程序一样,我们使用Helm chart。Kubernetes的Apache Spark操作器的Helm chart可以在这里找到。

Values & Helm 模板

我们更新values.yaml,然后运行helm template生成我们将部署到Kubernetes集群的清单。我们发现,对将要创建的内容具有可见性和对部署的控制是值得额外步骤的;模板存储在git中,我们的CD工具负责部署。

默认的chart values将允许你快速启动和运行。根据你的需要,以下是你可能需要做的一些修改:

  • 启用webhook:默认情况下,不启用Mutating Admission Webhook。启用允许自定义SparkApplication驱动程序和执行程序pod,包括挂载卷、ConfigMaps、亲和性/非亲和性等等。
  • 定义ingressUrlFormat:Spark UI可选的ingress。

请参阅快速入门指南和默认values.yaml获取更多详细信息和选项。

需求

要运行使用S3的SparkApplication,需要SparkApplication的附加配置,包括一个自定义docker镜像。Hadoop S3AConnector是一种可以对S3进行读写的工具。

1. 镜像更新

SparkApplication使用的docker镜像需要添加两个jar(hadoop-aws和aws-java-sdk或aws-java-sdk-bundle),版本根据Spark版本和Hadoop配置文件。

在这一步中有几件事情要记住。

  • 用户和权限
  • 额外的Jar

如果使用spark镜像作为起点,在添加jar时引用它们各自的dockerfile以正确对齐用户和位置。

让我们来看看python Dockerfile。在执行任何安装任务之前,用户被设置为root,然后重置为${spark_uid}。

通过检查基本镜像,可以看到jar位于/opt/spark/jars或$SPARK_HOME/jars中。最后,更新jar的权限,以便能够使用它们。

上传到S3的文档提供了使用jar文件的信息;然而,我们需要一个包含fs.s3a.path.style.access配置的新Hadoop版本——我们将在后面一节中讨论这个问题。在编写本文时,我们使用spark操作器版本v1beta2-1.2.0-3.0.0,其中包含基本spark版本3.0.0。使用gcr.io/spark-operator/spark-py:v3.0.0-hadoop3镜像作为起点,我们添加了以下jar:hadoop-aws-3.1.0.jar和aws-java-sdk-bundle-1.11.271.jar。它需要一些实验来确定最终能工作的正确镜像组合。

2. SparkApplication配置

SparkApplication需要额外的配置才能与S3通信。spec.sparkConf中要求的最小配置如下:

sparkConf:
    spark.hadoop.fs.s3a。端点:<端点>
    spark.hadoop.fs.s3a。impl: org.apache.hadoop.fs.s3a.S3AFileSystem

还必须提供访问S3的凭据。有类似于上面的配置选项;但是,这是非常丧气的,因为它们是字符串值,因此与安全最佳实践相违背。

3. S3凭证

我们不在SparkApplication的sparkConf中提供s3凭据,而是创建一个Kubernetes秘密,并为驱动程序和执行程序定义环境变量。Spark操作器文档提供了几种使用secret的选项,以及用于挂载秘密指定环境变量的完整示例。

接下来,因为我们使用环境变量来验证S3,我们在sparkConf中设置以下选项:

sparkConf:
     spark.hadoop.fs.s3a.aws.credentials.provider: com.amazonaws.auth.EnvironmentVariableCredentialsProvider

这是不需要的,如果没有提供,将尝试按照以下顺序来尝试凭据提供程序类:

  1. org.apache.hadoop.fs.s3a.SimpleAWSCredentialsProvider
  2. com.amazonaws.auth.EnvironmentVariableCredentialsProvider
  3. com.amazonaws.auth.InstanceProfileCredentialsProvider

4. S3样式

在SparkApplication的sparkConf中有一些其他的选项需要记住,这些选项是基于你特定的S3的:

sparkConf:
    extraJavaOptions: -Dcom.amazonaws.services.s3.enableV4=true
    spark.hadoop.fs.s3a.path.style.access: “true”
    spark.hadoop.fs.s3a.connection.ssl.enabled: “true”

路径样式访问——通过启用路径样式访问,将禁用虚拟主机(默认启用)。启用路径样式访问可以消除为默认虚拟主机设置DNS的需求。

启用SSL——如果你正在使用TLS/SSL,请确保在SparkApplication的sparkConf中启用这个选项。

额外的Java选项——根据你的需要而变化。

使用S3

现在你已经完成了使用S3的所有设置,现在有两种选择:利用S3处理依赖项或上传到S3。

S3处理依赖项

mainApplicationFile和spark作业使用的附加依赖项(包括文件或jar)也可以从S3中存储和获取。它们可以在spec.deps字段中的SparkApplication中与其他依赖项一起定义。spark-submit会分别使用spec.deps.jar和spec.deps.files中指定的jar或文件。s3中访问依赖的格式为s3a://bucket/path/to/file。

上传到S3

上传到S3时,文件位置的格式为s3a://bucket/path/to/destination。bucket必须存在,否则上传失败。如果destination文件已经存在,上载将失败。

总结

我们介绍了启动并运行Spark操作器和S3所需的4个步骤:镜像更新、SparkApplication的sparkConf中所需的选项、S3凭据以及基于特定S3的其他选项。最后,我们给出了一些关于如何利用S3来实现依赖关系和上传到S3的建议。

最后,我们帮助我们的内部客户,数据仓库团队,将他们的大数据工作负载从原生Apache Spark转移到Kubernetes。Kubernetes上的Spark操作器在云计算方面有很大的优势,我们想与更大的社区分享我们的经验。我们希望这个关于Spark操作器和S3集成的演练将帮助你和/或你的团队启动并运行Spark操作器和S3。

点击阅读网站原文


CNCF (Cloud Native Computing Foundation)成立于2015年12月,隶属于Linux  Foundation,是非营利性组织。
CNCF(云原生计算基金会)致力于培育和维护一个厂商中立的开源生态系统,来推广云原生技术。我们通过将最前沿的模式民主化,让这些创新为大众所用。扫描二维码关注CNCF微信公众号。
image

查看原文

赞 0 收藏 0 评论 0

Donald 发布了文章 · 1月19日

Falcosidekick + Kubeless = Kubernetes响应引擎

2020年CNCF中国云原生调查

10人将获赠CNCF商店$100美元礼券!

[](https://mp.weixin.qq.com/s?__...你填了吗?

image

问卷链接(https://www.wjx.cn/jq/9714648...


作者:Thomas Labarussias

两年前,我们向你们展示了一个基于 Falco 的 Kubernetes 响应引擎(Kubernetes Response Engine)。其想法是触发无 Kubeless 无服务器的函数来删除受感染的 pod,启动 Sysdig 捕获或将事件转发给 GCP PubSub。见README

为了避免维护这个自定义堆栈,我们与社区一起努力将所有组件集成到Falcosidekick中,并改进用户体验。在上一个版本 2.20.0 中,我们有了最后的部分,将 Kubeless 集成为原生输出。更多细节请参见我们的2020 年回顾

在这篇博文中,我们将解释使用 Falco + Falcosidekick + Kubeless 堆栈将你自己的响应引擎集成到 K8s 中的基本概念。

需求

我们需要 kubernetes 集群,至少运行 1.17 版本,并安装 helm 和 kubectl。

安装 Kubeless

跟随官方快速入门页面:

export RELEASE=$(curl -s https://api.github.com/repos/kubeless/kubeless/releases/latest | grep tag_name | cut -d '"' -f 4)
kubectl create ns kubeless
kubectl create -f https://github.com/kubeless/kubeless/releases/download/$RELEASE/kubeless-$RELEASE.yaml

几秒钟后,我们可以检查控制器是否启动并运行:

kubectl get pods -n kubeless
NAME                                          READY   STATUS    RESTARTS   AGE
kubeless-controller-manager-99459cb67-tb99d   3/3     Running   3          2m34s

安装 Falco

首先,我们将创建命名空间给 Falco 和 Falcosidekick:

kubectl create ns falco

增加 helm 仓库:

helm repo add falcosecurity https://falcosecurity.github.io/charts

在实际的项目中,你应该使用 helm pull falcosecurity/falco --untar 获取整个 chart,然后配置 values.yaml。在本教程中,我们会尽量简化操作,直接通过 helm install 命令设置配置:

helm install falco falcosecurity/falco --set falco.jsonOutput=true --set falco.httpOutput.enabled=true --set falco.httpOutput.url=http://falcosidekick:2801 -n falco

你应该得到这样的输出:

NAME: falco
LAST DEPLOYED: Thu Jan 14 23:43:46 2021
NAMESPACE: falco
STATUS: deployed
REVISION: 1
TEST SUITE: None
NOTES:
Falco agents are spinning up on each node in your cluster. After a few
seconds, they are going to start monitoring your containers looking for
security issues.
No further action should be required.

你可以看到你的新 Falco pod:

kubectl get pods -n falco
NAME                           READY   STATUS        RESTARTS   AGE
falco-ctmzg                    1/1     Running       0          111s
falco-sfnn8                    1/1     Running       0          111s
falco-rrg28                    1/1     Running       0          111s

参数(--set falco.jsonOutput=true --set falco.httpOutput.enabled=true --set falco.httpOutput.url=http://falcosidekick:2801)在那里配置事件的格式和Falco将发送事件的URL。由于Falco和Falcosidekick位于同一个命名空间中,我们可以直接使用服务的名称(Falcosidekick)。

安装 Falcosidekick

过程是挺一样的:

helm install falcosidekick falcosecurity/falcosidekick --set config.kubeless.namespace=kubeless --set config.kubeless.function=delete-pod -n falco

你应该得到这样的输出:

NAME: falcosidekick
LAST DEPLOYED: Thu Jan 14 23:55:12 2021
NAMESPACE: falco
STATUS: deployed
REVISION: 1
NOTES:
1. Get the application URL by running these commands:
  export POD_NAME=$(kubectl get pods --namespace falco -l "app.kubernetes.io/name=falcosidekick,app.kubernetes.io/instance=falcosidekick" -o jsonpath="{.items[0].metadata.name}")
  kubectl port-forward $POD_NAME 2801:2801
  echo "Visit http://127.0.0.1:2801 to use your application"

我们检查日志:

kubectl logs deployment/falcosidekick -n falco
2021/01/14 22:55:31 [INFO]  : Enabled Outputs : Kubeless
2021/01/14 22:55:31 [INFO]  : Falco Sidekick is up and listening on port 2801

Kubeless 显示为 enabled 输出,一切正常 👍。

简单说明参数:

  • config.kubeless.namespace:是 Kubeless 将运行的命名空间
  • config.kubeless.function:是 Kubeless 函数的名称

就是这样,我们真的试图得到一个很好的 UX😉。

安装 Kubeless 函数

我们不会解释如何编写或如何工作 Kubeless 函数,请阅读官方文档了解更多信息。

我们真正基本的函数将从 Falco 接收事件(通过 Falcosidekick),检查触发的规则是否在容器中的终端 Shell(参见规则),从事件字段中提取命名空间和 pod 名称,并删除相应的 pod:

from kubernetes import client,config

config.load_incluster_config()

def delete_pod(event, context):
    rule = event['data']['rule'] or None
    output_fields = event['data']['output_fields'] or None

    if rule and rule == "Terminal shell in container" and output_fields:
        if output_fields['k8s.ns.name'] and output_fields['k8s.pod.name']:
            pod = output_fields['k8s.pod.name']
            namespace = output_fields['k8s.ns.name']
            print (f"Deleting pod \"{pod}\" in namespace \"{namespace}\"")
            client.CoreV1Api().delete_namespaced_pod(name=pod, namespace=namespace, body=client.V1DeleteOptions())

基本上,这个过程是:

           +----------+                 +---------------+                    +----------+
           |  Falco   +-----------------> Falcosidekick +--------------------> Kubeless |
           +----^-----+   sends event   +---------------+      triggers      +-----+----+
                |                                                                  |
detects a shell |                                                                  |
                |                                                                  |
           +----+-------+                                   deletes                |
           | Powned Pod <----------------------------------------------------------+
           +------------+

在部署我们的函数之前,我们需要为它创建一个 ServiceAccount,因为它需要在任何命名空间中删除 pod 的权限:

cat <<EOF | kubectl apply -n kubeless -f -
apiVersion: v1
kind: ServiceAccount
metadata:
  name: falco-pod-delete
---
kind: ClusterRole
apiVersion: rbac.authorization.k8s.io/v1
metadata:
  name: falco-pod-delete-cluster-role
rules:
  - apiGroups: [""]
    resources: ["pods"]
    verbs: ["get", "list", "delete"]
---
kind: ClusterRoleBinding
apiVersion: rbac.authorization.k8s.io/v1
metadata:
  name: falco-pod-delete-cluster-role-binding
roleRef:
  kind: ClusterRole
  name: falco-pod-delete-cluster-role
  apiGroup: rbac.authorization.k8s.io
subjects:
  - kind: ServiceAccount
    name: falco-pod-delete
    namespace: kubeless
EOF
namespace: kubelessetetion.k8s.io
serviceaccount/falco-pod-delete created
clusterrole.rbac.authorization.k8s.io/falco-pod-delete-cluster-role created
clusterrolebinding.rbac.authorization.k8s.io/falco-pod-delete-cluster-role-binding created

只剩下函数本身的安装:

cat <<EOF | kubectl apply -n kubeless -f -
apiVersion: kubeless.io/v1beta1
kind: Function
metadata:
  finalizers:
    - kubeless.io/function
  generation: 1
  labels:
    created-by: kubeless
    function: delete-pod
  name: delete-pod
spec:
  checksum: sha256:a68bf570ea30e578e392eab18ca70dbece27bce850a8dbef2586eff55c5c7aa0
  deps: |
    kubernetes>=12.0.1
  function-content-type: text
  function: |-
    from kubernetes import client,config

    config.load_incluster_config()

    def delete_pod(event, context):
        rule = event['data']['rule'] or None
        output_fields = event['data']['output_fields'] or None

        if rule and rule == "Terminal shell in container" and output_fields:
            if output_fields['k8s.ns.name'] and output_fields['k8s.pod.name']:
                pod = output_fields['k8s.pod.name']
                namespace = output_fields['k8s.ns.name']
                print (f"Deleting pod \"{pod}\" in namespace \"{namespace}\"")
                client.CoreV1Api().delete_namespaced_pod(name=pod, namespace=namespace, body=client.V1DeleteOptions())
  handler: delete-pod.delete_pod
  runtime: python3.7
  deployment:
    spec:
      template:
        spec:
          serviceAccountName: falco-pod-delete
EOF
function.kubeless.io/delete-pod created

在这里,过了一会儿,我们有了一个 Kubeless 函数在命名空间 Kubeless 中运行,它可以由端口 8080 上的服务 delete-pod 触发:

kubectl get pods -n kubeless

NAME                                          READY   STATUS    RESTARTS   AGE
kubeless-controller-manager-99459cb67-tb99d   3/3     Running   3          3d14h
delete-pod-d6f98f6dd-cw228                    1/1     Running   0          2m52s
kubectl get svc -n kubeless

NAME         TYPE        CLUSTER-IP      EXTERNAL-IP   PORT(S)          AGE
delete-pod   ClusterIP   10.43.211.201   <none>        8080/TCP         4m38s

测试函数

我们从创建一个 pod 开始:

kubectl run alpine -n default --image=alpine --restart='Never' -- sh -c "sleep 600"
kubectl get pods -n default
NAME     READY   STATUS    RESTARTS   AGE
alpine   1/1     Running   0          9s

让我们在里面运行一个shell命令,看看会发生什么:

kubectl exec -i --tty alpine -n default -- sh -c "uptime"

23:44:25 up 1 day, 19:11,  load average: 0.87, 0.77, 0.77

正如预期的那样,我们得到了命令的结果,但是,如果现在得到 pod 的状态:

kubectl get pods -n default
NAME     READY   STATUS        RESTARTS   AGE
alpine   1/1     Terminating   0          103s

💥已被终止💥

我们现在可以检查组件的日志了。

Falco:

kubectl logs daemonset/falco -n falco

{"output":"23:39:44.834631763: Notice A shell was spawned in a container with an attached terminal (user=root user_loginuid=-1 k8s.ns=default k8s.pod=alpine container=5892b41bcf46 shell=sh parent=<NA> cmdline=sh terminal=34817 container_id=5892b41bcf46 image=<NA>) k8s.ns=default k8s.pod=alpine container=5892b41bcf46","priority":"Notice","rule":"Terminal shell in container","time":"2021-01-14T23:39:44.834631763Z", "output_fields": {"container.id":"5892b41bcf46","container.image.repository":null,"evt.time":1610667584834631763,"k8s.ns.name":"default","k8s.pod.name":"alpine","proc.cmdline":"sh","proc.name":"sh","proc.pname":null,"proc.tty":34817,"user.loginuid":-1,"user.name":"root"}}

Falcosidekick:

kubectl logs deployment/falcosidekick -n falco

2021/01/14 23:39:45 [INFO]  : Kubeless - Post OK (200)
2021/01/14 23:39:45 [INFO]  : Kubeless - Function Response :
2021/01/14 23:39:45 [INFO]  : Kubeless - Call Function "delete-pod" OK

(注意,该函数不返回任何内容,这就是为什么消息日志是空的)

delete-pod 函数:

kubectl logs deployment/delete-pod -n kubeless

10.42.0.31 - - [14/Jan/2021:23:39:45 +0000] "POST / HTTP/1.1" 200 0 "" "Falcosidekick" 0/965744
Deleting pod "alpine" in namespace "default"

总结

通过这个非常简单的例子,我们只触及了可能性的表面,现在一切皆有可能,所以不要犹豫,请在Kubernetes Slack #falco上与我们分享你的评论、想法和成功。也欢迎你贡献

注 1:你在 Kubernetes 之外运行 Falcosidekick,但仍然想使用 Kubernetes 的输出?没有问题,你可以声明一个 kubeconfig 文件来使用。见README

注 2:对于那些想用 Knative 代替 Kubeless 的人来说,它很快就会出现 😉

Enjoy

点击阅读网站原文


CNCF (Cloud Native Computing Foundation)成立于2015年12月,隶属于Linux  Foundation,是非营利性组织。
CNCF(云原生计算基金会)致力于培育和维护一个厂商中立的开源生态系统,来推广云原生技术。我们通过将最前沿的模式民主化,让这些创新为大众所用。扫描二维码关注CNCF微信公众号。
image

查看原文

赞 0 收藏 0 评论 0

Donald 发布了文章 · 1月13日

你的Kubernetes成熟度是多少?

周五截止,你填了吗?

10人将获赠CNCF商店$100美元礼券!

来参与2020年CNCF中国云原生调查

Image

问卷链接(https://www.wjx.cn/jq/9714648...


客座文章作者:Danielle Cook,Fairwinds内容营销总监

无论你是Kubernetes的新手还是有部署经验,Kubernetes都有你需要克服的复杂性。Kubernetes成熟度模型(Kubernetes Maturity Model )提供了整个Kubernetes旅程的端到端概述,你要经历哪些阶段,以及在每个阶段你需要学习/承担哪些技能和活动。

Kubernetes成熟度模型的存在是为了帮助你自我识别你所处的阶段,了解环境中的差距,并获得关于增强和改进Kubernetes堆栈的见解。

当你使用成熟度模型时,要知道,如果你确实到达了某个阶段,你可能仍然需要重新访问以前的阶段。此外,要明白Kubernetes的成熟不是一夜之间发生的——它需要时间。Kubernetes成熟度模型应该作为一种工具来帮助你理解在你使用云原生的过程中需要关注的地方,或者需要帮助的地方。

这里我们提供了每个阶段的简要介绍。

第一阶段:准备

在采用Kubernetes时,第一阶段是准备工作。你正在考虑云原生和Kubernetes将如何帮助你实现业务和技术目标,它的成本是多少,以及你打算实现什么。在这里,理解并能够清晰地表达为什么云原生和Kubernetes对组织很重要是至关重要的。一些核心概念包括理解云原生计算、容器和Kubernetes的价值和影响。

第二阶段:转型

转型是你转向Kubernetes的阶段。在这个阶段,你将通过部署第一个集群和工作负载来验证你的基础知识和理解。在转型阶段,你应该对基础知识有所准备,但同时可能缺乏完成该阶段所需的专业知识。你将在转换阶段花费大量时间。当你从事一些关键活动时,它涵盖了你的初始实现、迁移和学习曲线。当你采用Kubernetes时,不要被“启动并运行”的文章所愚弄。

第三阶段:部署

当你达到这个阶段,你和你的团队将有基本覆盖。一个应用程序或服务现在已经在生产环境中运行,外部依赖关系已经正确地投入使用,流量已经通过负载均衡器路由到Kubernetes,并且可以访问日志和指标。你还会有自动缩放功能。在Kubernetes成熟度模型的这个阶段,你可以完成从实现构建和部署流程、设置CI/CD、增强开发人员的能力以及引入一些有限的监视和可观察性等所有工作。

第四阶段:建立信心

随着Kubernetes环境的成熟,你将奠定了坚实的基础。现在,当你到达成熟度模型的第四阶段时,就该建立信心了。在第三阶段,你启动并运行了Kubernetes基础设施。第四阶段是你开始理解Kubernetes的细微差别的时候。重要的是要记住,建立信心需要时间,你会重复任务和经历类似的情况。

第五阶段:改进操作

你正在积极地在业务中成功地部署Kubernetes。现在你想要提高Kubernetes集群的安全性、效率和可靠性。

第六阶段:测量与控制

Kubernetes成熟的下一个阶段是引入更多的环境度量和控制。你和你的团队在Kubernetes中运行良好,对Kubernetes有全面的了解,并在整个组织范围内采用。你将对Kubernetes有更深入的功能理解,并对在集群和整个环境中应该如何做事情有更深入的见解。此外,团队已经准备好处理以前阶段的技术债务。前几个阶段引入了一些监控和可观察性。在这个阶段,你将收集和处理更多的数据、见解和工具,以便开始理解要度量和跟踪什么,以及如何控制Kubernetes。

第七阶段:优化和自动化

随着Kubernetes的完全成熟,你现在将集中精力优化和自动化你的环境。这包括优化Kubernetes的成本和效率,尽可能地实现自动化,并定期运行配置验证以检查错误。

你可以在https://www.fairwinds.com/kub...。它应该作为一种工具,帮助你的云原生旅程。

点击阅读网站原文


CNCF (Cloud Native Computing Foundation)成立于2015年12月,隶属于Linux  Foundation,是非营利性组织。
CNCF(云原生计算基金会)致力于培育和维护一个厂商中立的开源生态系统,来推广云原生技术。我们通过将最前沿的模式民主化,让这些创新为大众所用。扫描二维码关注CNCF微信公众号。
image

查看原文

赞 0 收藏 0 评论 0

Donald 发布了文章 · 1月11日

使用Falco检测Kubernetes安全问题简介

周五截止,你填了吗?

10人将获赠CNCF商店$100美元礼券!

来参与2020年CNCF中国云原生调查

Image

问卷链接(https://www.wjx.cn/jq/9714648...


作者:Frederick Fernando。本文于2020年12月16日首次发表在InfraCloud的博客上。

我们来谈谈Kubernetes的安全问题

随着Kubernetes的不断普及,了解如何保护它是很重要的。在Kubernetes等动态基础设施平台中,检测和处理威胁很重要,但同时也具有挑战性。

开源云原生运行时安全项目Falco是Kubernetes威胁检测引擎中领先的开源引擎之一。Falco由Sysdig在2016年创建,是第一个作为孵化级项目加入CNCF的运行时安全项目。Falco检测意外的应用程序行为,并在运行时发出威胁警报。

为什么这么难?

根据这一分析,安全是运行Kubernetes的一个更困难的挑战。困难的原因是,在云原生堆栈中有多个移动层,因此运营者可能不会在一开始就关注安全性。另一个因素是Kubernetes的一些发行版在默认情况下可能并不安全,这与运营者的假设相反。

预防和检测

信息安全是一个通过不同阶段进行自我建设和加强的过程。安全是一段旅程,而不是目的地。虽然信息安全过程有多种策略和活动,但我们可以将它们全部分为三个不同的阶段——预防、检测和响应。

预防措施

预防措施包括适当的访问控制、身份验证和授权。不管一个系统可能拥有何种程度的保护,它都会因为更大程度的动机和技能而受到影响。没有万无一失的“银弹”安全解决方案。应该部署深度防御策略,这样当每一层发生故障时,它就安全故障到一个已知的状态,并发出警报。这一战略的最重要因素是及时发现并通知遭到入侵。

检测措施

检测措施的一个例子包括从安全和网络设备,如基于主机的入侵检测系统(HIDS)和网络入侵检测系统(NIDS),向SIEM发送日志,并建立规则,在发现可疑活动时发出警报。根据深度防御的方法,我们应该在技术堆栈的多个层次上审计和放置检测触发器,从查看云审计日志(如Cloudtrail)、Kubernetes集群、容器、应用程序代码、主机操作系统和内核。我们将在这个博客中看看这些检测措施,这些措施将进一步帮助我们应对这些威胁。

image
图片来源:@leodido

在Kubernetes上设置Falco

运行Falco最安全的方法是直接在主机系统上安装Falco,这样Falco就可以与Kubernetes隔离。然后,可以通过运行在Kubernetes中的只读代理使用Falco警报。如果不需要隔离,Falco也可以直接在Kubernetes运行。我们将在本教程中使用Helm设置Falco,但你应该意识到你所选择的方法的利弊。

步骤

前提条件:为此我们需要一个有效的Kubernetes设置。你可以使用AWS/GCP提供的云Kubernetes,也可以使用minikube在本地设置一个。我们还要求kubectl和Helm安装在你的客户端机器上。

让我们从Falco的安装开始。

  1. 在Helm中添加falcosecurity仓库
$ helm repo add falcosecurity https://falcosecurity.github.io/charts
 
$ helm repo update
Hang tight while we grab the latest from your chart repositories...
...Successfully got an update from the "falcosecurity" chart repository
...Successfully got an update from the "stable" chart repository
Update Complete. ⎈Happy Helming!⎈
  1. 安装chart
$ helm install falco falcosecurity/falco
NAME: falco
LAST DEPLOYED: Mon Nov 9 22:09:28 2020
NAMESPACE: default
STATUS: deployed
REVISION: 1
TEST SUITE: None
NOTES:
Falco agents are spinning up on each node in your cluster. After a few
seconds, they are going to start monitoring your containers looking for
security issues.
No further action should be required.
  1. 几秒钟后Falco应该开始运行,验证一下,你马上就会看到你创建的pod。
$ helm ls
 
$ kubectl get pods

设置环境

我们需要一个环境来模拟攻击并检测它们。我们来设置一下。我们要用Helm。

让我们添加Helm的stabel仓库,并从其中安装mysql-db chart。

$ helm repo add stable https://charts.helm.sh/stable
$ helm repo update
Hang tight while we grab the latest from your chart repositories...
...Successfully got an update from the "falcosecurity" chart repository
...Successfully got an update from the "stable" chart repository
Update Complete. ⎈Happy Helming!⎈
$ helm install mysql-db stable/mysql
NAME: mysql-db
LAST DEPLOYED: Mon Nov 9 22:11:07 2020
NAMESPACE: default
STATUS: deployed
REVISION: 1
NOTES:
MySQL can be accessed via port 3306 on the following DNS name from within your cluster:
mysql-db.default.svc.cluster.local
…

现在让我们监控Falco日志:

$ kubectl get pods
NAME                      READY  STATUS   RESTARTS  AGE
falco-6rr9r               1/1    Running  0         49m
mysql-db-d5dc6b85d-77hrm  1/1    Running  0         47m
ubuntu                    1/1    Running  0         43m
$ kubectl logs -f falco-6rr9r # Replace with your Falco pod name here

Falco的日志分析

攻击者在访问Kubernetes集群后所做的第一步是枚举可用的网络主机。攻击者会试图在一个看似陌生的环境中寻找出路。他们可以尝试使用安全/较少噪音的命令来从集群中获得更多的信息。让我们看看攻击者可能会做的步骤,并看看来自Falco的相应检测信号。我们将使用Falco附带的默认规则集,这些规则可以根据你的环境需要进行调整。你可以在这里找到Falco的默认规则:
https://github.com/falcosecur...

容器内的终端

描述:探测到在pod中产生的终端。我们在运行的pod上打开一个终端外壳来复制这个场景。

$ kubectl exec -it mysql-db-d5dc6b85d-77hrm -- bash -il # Replace with the mysql pod name you have

检测:

18:08:40.584075795: Notice A shell was spawned in a container with an attached terminal (user=root user_loginuid=-1 k8s.ns=default k8s.pod=mysql-db-d5dc6b85d-77hrm container=3fc8155f9d1a shell=bash parent=runc cmdline=bash -il terminal=34816 container_id=3fc8155f9d1a image=mysql) k8s.ns=default k8s.pod=mysql-db-d5dc6b85d-77hrm container=3fc8155f9d1a

从容器联系Kubernetes API服务器

描述:我们运行kube-recon,这是一个在Kubernetes环境中进行初步侦察的工具。该规则检测从容器联系Kubernetes API服务器的尝试。

$ kubectl run kuberecon --tty -i --image octarinesec/kube-recon
/ # ./kube-recon
2020/11/09 18:21:22 Testing K8S API permissions
2020/11/09 18:21:23 Your K8S API Server is configured properly
2020/11/09 18:21:23 Running Nmap on the discovered IPs
2020/11/09 18:21:23 Getting local ip address and subnet
2020/11/09 18:21:23 Trying to download EICAR file
2020/11/09 18:21:23 Downloaded EICAR successfully. No malware protection is in place

检测:

18:20:45.927730981: Notice A shell was spawned in a container with an attached terminal (user=root user_loginuid=-1 k8s.ns=<NA> k8s.pod=<NA> container=4f63870599d0 shell=sh parent=<NA> cmdline=sh terminal=34816 container_id=4f63870599d0 image=octarinesec/kube-recon) k8s.ns=<NA> k8s.pod=<NA> container=4f63870599d0
18:21:22.657590195: Warning Docker or kubernetes client executed in container (user=root user_loginuid=-1 k8s.ns=default k8s.pod=kuberecon container=4f63870599d0 parent=kube-recon cmdline=kubectl get pods image=octarinesec/kube-recon:latest) k8s.ns=default k8s.pod=kuberecon container=4f63870599d0
18:21:22.723707794: Notice Unexpected connection to K8s API Server from container (command=kubectl get pods k8s.ns=default k8s.pod=kuberecon container=4f63870599d0 image=octarinesec/kube-recon:latest connection=172.17.0.5:56972->10.96.0.1:443) k8s.ns=default k8s.pod=kuberecon container=4f63870599d0

检查shell是否是一个容器环境(更改线程名称空间)

描述:amicontained是一个检查终端是否为容器化环境的工具。该规则检测更改程序/线程名称空间的尝试。

$ cd /tmp; curl -L -o amicontained https://github.com/genuinetools/amicontained/releases/download/v0.4.7/amicontained-linux-amd64; chmod 555 amicontained; ./amicontained
Output: 
Container Runtime: docker
Has Namespaces:
 pid: true
 user: false
AppArmor Profile: kernel
Capabilities:
 BOUNDING -> chown dac_override fowner fsetid kill setgid setuid setpcap net_bind_service net_raw sys_chroot mknod audit_write setfcap
Seccomp: disabled 
Blocked Syscalls (19):
 MSGRCV SYSLOG SETSID VHANGUP PIVOT_ROOT ACCT SETTIMEOFDAY UMOUNT2 SWAPON SWAPOFF REBOOT SETHOSTNAME SETDOMAINNAME INIT_MODULE DELETE_MODULE LOOKUP_DCOOKIE KEXEC_LOAD OPEN_BY_HANDLE_AT FINIT_MODULE

检测:

18:43:37.288344192: Notice Namespace change (setns) by unexpected program (user=root user_loginuid=-1 command=amicontained parent=bash k8s.ns=default k8s.pod=kuberecon container=c6112967b4f2 container_id=c6112967b4f2 image=octarinesec/kube-recon:latest) k8s.ns=default k8s.pod=kuberecon container=c6112967b4f2
Mon Nov 9 18:43:37 2020: Falco internal: syscall event drop. 9 system calls dropped in last second.
18:43:37.970973376: Critical Falco internal: syscall event drop. 9 system calls dropped in last second. (ebpf_enabled=0 n_drops=9 n_drops_buffer=0 n_drops_bug=0 n_drops_pf=9 n_evts=15232)

总结

在本教程中,我们了解了Kubernetes安全监视的基础知识,以及Falco如何允许我们使用规则来检测安全问题。Falco的默认检测规则集足以让你启动并运行,但是你很可能需要在默认规则集的基础上进行构建。如果你有任何反馈或建议,请通过Twitter @securetty_与我联系。

点击阅读网站原文


CNCF (Cloud Native Computing Foundation)成立于2015年12月,隶属于Linux  Foundation,是非营利性组织。
CNCF(云原生计算基金会)致力于培育和维护一个厂商中立的开源生态系统,来推广云原生技术。我们通过将最前沿的模式民主化,让这些创新为大众所用。扫描二维码关注CNCF微信公众号。
image

查看原文

赞 0 收藏 0 评论 0

Donald 发布了文章 · 1月8日

欢迎Flagger加入Flux项目

你填了吗?

10人将获赠CNCF商店$100美元礼券!

来参与2020年CNCF中国云原生调查

Image

问卷链接(https://www.wjx.cn/jq/9714648...


image

Flagger通过Canary发布、A/B测试和Blue/Green等渐进的交付策略扩展了Flux功能,它是专门为GitOps风格的交付而设计的。

自从GitOps工具包诞生以来,很明显fluxcd/将成为一个与GitOps相关的项目家族。Flagger维护人员期望使用工具箱组件并以这种方式简化Flagger。根据“Flagger项目家族”来巩固代码库和思维,并相应地制定路线图,这将使两个社区整体受益。

两位Flagger维护者(Stefan Prodan和Takeshi Yoneda)很高兴看到这一切的发生。也要感谢Weaveworks同意将Flagger及其版权转让给Flux(也就是CNCF)。

Flagger即将发布的路线图现在包括了GitOps工具包的集成

请帮助我们推动这个项目向前发展!

也感谢为最新两个版本做出贡献的每一个人:

  • Flagger 1.6.0:
  • 增加了对使用基于Gloo Edge HTTP头路由的A/B测试的支持
  • Flagger 1.5.0:
  • Flagger可以安装在多架构Kubernetes集群(Linux AMD64/ARM64/ARM)上。
  • 多架构镜像可以在GitHub仓库ghcr.io/fluxcd/flagger上找到。

点击阅读网站原文


CNCF (Cloud Native Computing Foundation)成立于2015年12月,隶属于Linux  Foundation,是非营利性组织。
CNCF(云原生计算基金会)致力于培育和维护一个厂商中立的开源生态系统,来推广云原生技术。我们通过将最前沿的模式民主化,让这些创新为大众所用。扫描二维码关注CNCF微信公众号。
image

查看原文

赞 0 收藏 0 评论 0

认证与成就

  • 获得 31 次点赞
  • 获得 1 枚徽章 获得 0 枚金徽章, 获得 0 枚银徽章, 获得 1 枚铜徽章

擅长技能
编辑

(゚∀゚ )
暂时没有

开源项目 & 著作
编辑

(゚∀゚ )
暂时没有

注册于 2018-12-13
个人主页被 3k 人浏览