From 1a931c92b6ab34dbe9d82a1f145d14fd7998ae92 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?=E7=8E=8B=E6=89=A7=E5=A7=AC?= <35649989+esterwang@users.noreply.github.com> Date: Mon, 1 Apr 2019 21:42:02 +0800 Subject: [PATCH 1/2] Create 2019-04-01-caasone-daily-news.md --- posts/2019-04-01-caasone-daily-news.md | 25 +++++++++++++++++++++++++ 1 file changed, 25 insertions(+) create mode 100644 posts/2019-04-01-caasone-daily-news.md diff --git a/posts/2019-04-01-caasone-daily-news.md b/posts/2019-04-01-caasone-daily-news.md new file mode 100644 index 0000000..7e689bd --- /dev/null +++ b/posts/2019-04-01-caasone-daily-news.md @@ -0,0 +1,25 @@ +--- +title: "技术日报(2019-04-01)" +date: 2019-04-01T00:00:00+08:00 +categories: [ "daily"] +draft: false +--- +### [容器时代]技术日报(20180922) + +1. PostgreSQL on Kubernetes: How to run a stateful legacy app on a stateless microservice http://www.bmc.com/blogs/kubernetes-postgresql/ +2. Securing a dockerized plumber API with SSL and Basic Authentication https://www.tuicool.com/articles/IrqQRbi +3. MicroK8s in the Wild https://blog.ubuntu.com/2019/03/28/microk8s-in-the-wild +4. Docker-06-持久化存储和数据共享 https://www.cnblogs.com/liuguangjiji/p/10630801.html +5. GoLang with Rails https://shwetakale.wordpress.com/2019/03/28/golang-with-rails/ + +编辑:@esterwang + +地址: + +[容器时代志愿编辑招募] + +### 其他 + +1、欢迎将自己的博文转载到公众号进一步推广 + +2、想翻译文章的同学现在就可开始 From c9c17be4aa832d73540470030e1e829f503d981c Mon Sep 17 00:00:00 2001 From: "liyao.mly" Date: Tue, 2 Jul 2019 12:55:36 +0800 Subject: [PATCH 2/2] fix conflicts --- ...ting with the Kubernetes Client Library.md | 234 ++++++++++-------- 1 file changed, 125 insertions(+), 109 deletions(-) diff --git a/translation/Unit Testing with the Kubernetes Client Library.md b/translation/Unit Testing with the Kubernetes Client Library.md index a6f6a08..e7200d4 100644 --- a/translation/Unit Testing with the Kubernetes Client Library.md +++ b/translation/Unit Testing with the Kubernetes Client Library.md @@ -1,157 +1,173 @@ -# 如何进行单元测试代码来调用Kubernetes API +使用Kubernetes客户端库进行单元测试 +============= -使用kubernetes客户机库可以帮助您模拟出一个集群来测试您的代码。 +如何对被 Kubernetes API 调用的代码进行单元测试? -在构建[kubernetes/minikube](https://github.com/kubernetes/minikube)时,作为[kubernetes/client-go ](https://github.com/kubernetes/client-go)库的第一个消费者之一,services、pods和deployments构建了详细的模拟,以单元测为例,现在,有一种更简单的方法可以用更少的代码行来做同样的事情。 +使用 Kubernetes 客户端库可以通过模拟集群来测试代码。 -我将演示如何测试一个简单的函数,该函数列出了集群中运行的所有容器镜像。你需要一个Kubernetes集群,我建议用GKE或桌面版的Docker。 +作为在构建 kubernetes / minikube 时,第一批使用kubernetes / client-go 库的用户之一,我曾经详尽的设计了服务、调度单元和部署来对我的代码进行单元测试。 现在,我发现有一种更简单的方法可以用更少的代码行来做同样的事情。 -## Setup -克隆示例存储库[https://github.com/r2d4/k8s-unit-test-example ](https://github.com/r2d4/k8s-unit-test-example ),如果要运行命令并以交互方式继续操作。 +我将演示如何测试一个**列出了集群中运行的所有容器映像**的简单的函数。我建议你用 GKE 或 Docker 作为桌面,并且你还需要一个 Kubernetes 集群。 -###main.go +### 安装程序 + +如果你想要运行命令并以交互方式继续操作,请克隆示例仓库 https://github.com/r2d4/k8s-unit-test-example 。 + +### main.go ```go -import ( - "github.com/pkg/errors" - meta_v1 "k8s.io/apimachinery/pkg/apis/meta/v1" - "k8s.io/client-go/kubernetes/typed/core/v1" -) -//ListImages返回在提供的命名空间中运行的容器映像的列表 -func ListImages(client v1.CoreV1Interface, namespace string) ([]string, error) { - pl, err := client.Pods(namespace).List(meta_v1.ListOptions{}) - if err != nil { - return nil, errors.Wrap(err, "getting pods") - } - var images []string - for _, p := range pl.Items { - for _, c := range p.Spec.Containers { - images = append(images, c.Image) - } +package main + +import ( + "github.com/pkg/errors" + meta_v1 "k8s.io/apimachinery/pkg/apis/meta/v1" + "k8s.io/client-go/kubernetes/typed/core/v1" +) + +// ListImages returns a list of container images running in the provided namespace +func ListImages(client v1.CoreV1Interface, namespace string) ([]string, error) { + pl, err := client.Pods(namespace).List(meta_v1.ListOptions{}) + if err != nil { + return nil, errors.Wrap(err, "getting pods") + } + + var images []string + for _, p := range pl.Items { + for _, c := range p.Spec.Containers { + images = append(images, c.Image) } - return images, nil - } + } + + return images, nil +} ``` - - -## Writing the Tests -从测试用例的定义开始,以及一些运行测试的框架代码。 + + + +### 编写测试 + +我们可以从测试用例的定义开始,运行一些测试的框架代码。 ```go func TestListImages(t *testing.T) { - var tests = []struct { - description string - namespace string - expected []string - objs []runtime.Object + var tests = []struct { + description string + namespace string + expected []string + objs []runtime.Object + }{ + {"no pods", "", nil, nil}, } - { - {"no pods", "", nil, nil}, - } - // 在这写需要测试的代码 -} -``` - -## What's Happening + // Actual testing code goes here... +} -这种编写测试的风格称为“表驱动测试”,在Go中,这是首选的样式。实际的测试代码迭代表条目并执行必要的测试。测试代码只写一次,用于每种情况。需要注意一些事情: +``` -* 用于保存测试用例定义的匿名结构。它们允许我们简洁地定义测试用例。 +#### 发生了什么 +这种编写测试的风格称为**“表驱动测试”**,是Go语言中首选的样式,实际测试代码会迭代表条目并执行必要的测试。测试代码只需要写一次,却可以适用于每种情况。我门可以注意到一些有趣的事情: -* 运行时对象切片objs将保存所有希望我们的模拟API服务器保存的运行时对象。将用一些pods填充,但是您可以在这里使用任何kubernetes对象。 - -* 琐碎的测试用例,服务器上没有pods不应返回任何image。 +- 测试用例的定义是用匿名结构保存的,因此我们可以简洁的定义测试用例。 +- 对象切片运行时,`objs`将保存我们的模拟 API 服务器保存的所有正在运行的对象,此处我们选择用一些调度单元来填充它,但其实可以在这里使用任何 Kubernetes 对象。 +- 如果测试用例非常琐碎,服务器上将没有调度单元,并且不返回任何图像。 +### 测试回路 -## Test Loop -填写将为每个测试用例运行的实际测试代码。 +让我们来为每个测试用例都写一段实际测试代码。 ```go -for _, test := range tests { - t.Run(test.description, func(t *testing.T) { - client := fake.NewSimpleClientset(test.objs...) - actual, err := ListImages(client.CoreV1(), test.namespace) - if err != nil { - t.Errorf("Unexpected error: %s", err) - return - } - if diff := cmp.Diff(actual, test.expected); diff != "" { - t.Errorf("%T differ (-got, +want): %s", test.expected, diff) - return - } - }) -} +for _, test := range tests { + t.Run(test.description, func(t *testing.T) { + client := fake.NewSimpleClientset(test.objs...) + actual, err := ListImages(client.CoreV1(), test.namespace) + if err != nil { + t.Errorf("Unexpected error: %s", err) + return + } + if diff := cmp.Diff(actual, test.expected); diff != "" { + t.Errorf("%T differ (-got, +want): %s", test.expected, diff) + return + } + }) + } ``` -需要注意的一些有趣的事情, -t.run运行执行子测试。为什么使用子测试? -* 可以使用-run flg to go test +在这里我们也可以注意到一些有趣的事情: -* 可以做设置和拆卸子测试是并行运行测试用例的入口(这里不做) +- 文件`t.Run` 的功能是执行子测试,那么为什么要使用子测试? -* 实际结果和预期结果与cmp.diff不同。diff返回两个值之间差异的人类可读报告。如果相同的输入值和选项的equal返回true,则返回空字符串。 +- - 你可以使用`-run` 命令运行特定的测试用例进行测试。 -fake.newsImpleClientSet返回将使用提供的对象响应的客户端集。 它由一个非常简单的对象跟踪器提供支持,该跟踪器按原样处理增加、更新和删除操作,不应用任何验证和/或默认值。 + - 你可以设置和清理测试代码 + - 子测试是同时运行测试用例的入口(这篇文章将不涉及) +- 实际结果和预期结果都与 `cmp.diff` 不同。Diff 返回的两个值之间差异是可读的,当且仅当输入值和选项相等且为真时,Diff返回空字符串。 -## Test Cases +`fake.NewSimpleClientset` 返回一个使用提供的对象进行响应的客户端集。它由一个非常简单的对象跟踪器支持,该跟踪器按原样处理创建、更新和删除操作,而不应用任何验证和默认值。 -  创建一个pod函数,它将帮助提供一些pod供我们测试。既然我们关心namespace和image,它基于这些参数创建新的pod. -   -``` -func pod(namespace, image string) *v1.Pod { - return &v1.Pod{ObjectMeta: meta_v1.ObjectMeta{Namespace: namespace}, Spec: v1.PodSpec{Containers: []v1.Container{{Image: image}}}} +### 测试用例 + +我们来创建一个调度单元助手函数,它将帮助我们提供一些测试的调度单元。由于我们关心的是命名空间和镜像,所以我们可以创建一个可以基于这些参数创建新的调度单元的助手。 + +```go +func pod(namespace, image string) *v1.Pod { + return &v1.Pod{ObjectMeta: meta_v1.ObjectMeta{Namespace: namespace}, Spec: v1.PodSpec{Containers: []v1.Container{{Image: image}}}} } ``` -  写三个单元测试。如果使用特殊的namespace值列出所有namespace中的pods,第一个方法将确保获取所有image。 -   -``` +我们来写三个单元测试。第一个方法能确保我门获取所有镜像,这时我们需要使用特殊的命名空间值 `“”` 来列出命名空间中所有的调度单元。 + +```go {"all namespaces", "", []string{"a", "b"}, []runtime.Object{pod("correct-namespace", "a"), pod("wrong-namespace", "b")}} ``` -  第二种情况将确保按namespace正确筛选,忽略错误namespace中的pod。 -``` +第二种方法能确保我们按名称空间正确筛选,忽略调度单元中的 `wrong-namespace` 。 + +```go {"filter namespace", "correct-namespace", []string{"a"}, []runtime.Object{pod("correct-namespace", "a"), pod("wrong-namespace", "b")}} ``` -  第三种情况将确保如果所需的namespace中没有pods,则不会返回任何内容。 -``` +第三种方法能确保如果所需的命名空间中没有调度单元,则不会返回任何内容。 + +```go {"wrong namespace", "correct-namespace", nil, []runtime.Object{pod("wrong-namespace", "b")}} ``` -#### Putting it all together + +把上面这些代码放在一起。 + ```go -func TestListImages(t *testing.T) { - var tests = []struct { - description string - namespace string - expected []string - objs []runtime.Object +func TestListImages(t *testing.T) { + var tests = []struct { + description string + namespace string + expected []string + objs []runtime.Object + }{ + {"no pods", "", nil, nil}, + {"all namespaces", "", []string{"a", "b"}, []runtime.Object{pod("correct-namespace", "a"), pod("wrong-namespace", "b")}}, + {"filter namespace", "correct-namespace", []string{"a"}, []runtime.Object{pod("correct-namespace", "a"), pod("wrong-namespace", "b")}}, + {"wrong namespace", "correct-namespace", nil, []runtime.Object{pod("wrong-namespace", "b")}}, } - { - {"no pods", "", nil, nil}, - {"all namespaces", "", []string{"a", "b"},[]runtime.Object{pod("correct-namespace", "a"), pod("wrong-namespace", "b")}}, - {"filter namespace", "correct-namespace", []string{"a"},[]runtime.Object{pod("correct-namespace", "a"), pod("wrong-namespace", "b")}}, - {"wrong namespace", "correct-namespace", nil,[]runtime.Object{pod("wrong-namespace", "b")}}, - } - for _, test := range tests { - t.Run(test.description, func(t *testing.T) { - client := fake.NewSimpleClientset(test.objs...) - actual, err := ListImages(client.CoreV1(), test.namespace) - if err != nil { + + for _, test := range tests { + t.Run(test.description, func(t *testing.T) { + client := fake.NewSimpleClientset(test.objs...) + actual, err := ListImages(client.CoreV1(), test.namespace) + if err != nil { t.Errorf("Unexpected error: %s", err) - return - } - if diff := cmp.Diff(actual, test.expected); diff != "" { + return + } + if diff := cmp.Diff(actual, test.expected); diff != "" { t.Errorf("%T differ (-got, +want): %s", test.expected, diff) - return + return } - }) - } - } + }) + } +} + ``` -Matt Rickard -[https://matt-rickard.com/kubernetes-unit-testing/](https://matt-rickard.com/kubernetes-unit-testing/) +### 原文链接 +[原文作者:@mattrickard] +[原文链接:https://matt-rickard.com/kubernetes-unit-testing/](https://matt-rickard.com/kubernetes-unit-testing/)