-
Notifications
You must be signed in to change notification settings - Fork 0
/
Copy pathsearchindex.json
1 lines (1 loc) · 66 KB
/
searchindex.json
1
{"categories":[{"title":"docker","uri":"https://whalecold.github.io/categories/docker/"},{"title":"go","uri":"https://whalecold.github.io/categories/go/"},{"title":"kubernetes","uri":"https://whalecold.github.io/categories/kubernetes/"},{"title":"linux","uri":"https://whalecold.github.io/categories/linux/"},{"title":"photography","uri":"https://whalecold.github.io/categories/photography/"},{"title":"tools","uri":"https://whalecold.github.io/categories/tools/"},{"title":"work-note","uri":"https://whalecold.github.io/categories/work-note/"}],"posts":[{"content":"大概是和 oom 杠上了 - -!\n今天遇到一个比较奇怪的问题,在平台自己的监控数据查看某个 Pod 的时候发现只用了 30m, 并且 limit 设置的是 100m, 但是发现 OOM 了。 通过使用命令 kubectl top pod \u0026lt;podName\u0026gt; 获取到的内存占用也是 30m,所以初步怀疑是系统的 OOM 造成的。\n登陆到 Pod 所在节点后,使用 dmesg -T | grep Kill 命令查看了下日志,找到 Pod 中记录 OOM 的时间点,找到对应的日志,如下:\n[Mon Dec 30 14:02:31 2019] Memory cgroup out of memory: Kill process 3689454 (reference) score 1215 or sacrifice child [Mon Dec 30 14:02:31 2019] Killed process 3689409 (reference), UID 0, total-vm:707908kB, anon-rss:19312kB, file-rss:5520kB, shmem-rss:0kB 显示的是被 cgroup 的限制给杀掉的。这里补充下,OOM 有两个原因:\n 操作系统的 OOM cgroup 的 OOM, 这种情况是由于 Pod 中的 Container 设置的 limit, 当使用资源超过 limit 的时候会触发 OOM. 这里又去 Prometheus 查询了下数据, 发现有好几条数据,最上面的那条是 Pod 的 container_memory_usage_bytes, 确实达到了 100M, 而下面的两条数据分别是这个 Pod 下 Container 的数据,按理来说下面数据的加起来等于 Pod 的数据才对,这里怀疑是不是 Prometheus 出错了,所以准备去查看系统的 cgroup 信息。\n登陆到对应节点的主机。在目录 /sys/fs/cgroup/memory/kubepods/ 下会有几个文件夹:besteffort、burstable 和 guaranteed,查看下 Pod 的 QosClass 进入对应的目录,然后会看到很多类似于 pod051f90c3-2ac0-11ea-a9b5-525400003709 这样的目录,这里的拼写规则是 pod + pod.uid 来的,所以很容易就可以进入指定 Pod 的目录下,大概会看到一下! 这里的 memory.max_usage_in_bytes 保存的就是当前 Pod 的使用情况,然后再分别进入两个容器目录下查看了对应的内存和 Prometheus 看到基本一致。同事告诉我这是 cgroup 的一个 bug,在新版本的内核中已经修复了。去 github 上找了下有个类似的 issue, 里面有人尝试 echo 1 \u0026gt; /sys/fs/cgroup/memory/docker/memory.force_empty 去解决问题, 但是今天试的时候发现报错 -bash: echo: write error: Device or resource busy,目前的解决办法是杀掉这个 Pod 然后让 k8s 起一个新的。\n记录下当前的内核版本\nLinux kube-node-2 3.10.0-1062.el7.x86_64 #1 SMP Wed Aug 7 18:08:02 UTC 2019 x86_64 x86_64 x86_64 GNU/Linux 顺便记录一个链接\nhttps://ops.tips/blog/why-top-inside-container-wrong-memory/ ","id":0,"section":"posts","summary":"\u003cp\u003e大概是和 oom 杠上了 - -!\u003c/p\u003e","tags":["kubernetes","linux","cgroup"],"title":"k8s oom 排查记录(二)","uri":"https://whalecold.github.io/2019/12/k8s-oom-%E6%8E%92%E6%9F%A5%E8%AE%B0%E5%BD%95%E4%BA%8C/","year":"2019"},{"content":"","id":1,"section":"posts","summary":"","tags":["index"],"title":"Posts","uri":"https://whalecold.github.io/posts/","year":"2019"},{"content":"golang unit test\n在软件开发的过程中或多或少的引入一些 bug,而排查 bug 的难易程度也有一下分布\nself check \u0026lt; unit test \u0026lt; smoke test \u0026lt; qa test \u0026lt; production accident 以上对产品的影响也是逐级递增的,所以越早发现 bug 对后期的影响也会越小,这里就记录下 golang 中单元测试(Test-driven development)的技巧和规范:\nTableDrivenTests 在之前写测试代码的时候经常发现自己写一个新的用例都是用的 copy 和 paste,写多了的时候我们是不是可以停下来想下有什么好的办法去减少重复劳动, 官方有推荐了一种方法 table-driven tests:\n 初始化一个测试用例列表,每个 entry 中包含了输入和预期结果,还可以包含一些提高阅读性的额外信息,如 name 等,然后遍历这个数组,去执行测试代码,对于代码的执行结果和预期结果。这样每次添加新的用例的时候只需要添加一个新的 entry 即可,不再需要复制粘贴了。 下面是一个例子:\nvar flagtests = []struct { in string out string }{ {\u0026quot;%a\u0026quot;, \u0026quot;[%a]\u0026quot;}, {\u0026quot;%-a\u0026quot;, \u0026quot;[%-a]\u0026quot;}, {\u0026quot;%+a\u0026quot;, \u0026quot;[%+a]\u0026quot;}, {\u0026quot;%#a\u0026quot;, \u0026quot;[%#a]\u0026quot;}, {\u0026quot;% a\u0026quot;, \u0026quot;[% a]\u0026quot;}, {\u0026quot;%0a\u0026quot;, \u0026quot;[%0a]\u0026quot;}, {\u0026quot;%1.2a\u0026quot;, \u0026quot;[%1.2a]\u0026quot;}, {\u0026quot;%-1.2a\u0026quot;, \u0026quot;[%-1.2a]\u0026quot;}, {\u0026quot;%+1.2a\u0026quot;, \u0026quot;[%+1.2a]\u0026quot;}, {\u0026quot;%-+1.2a\u0026quot;, \u0026quot;[%+-1.2a]\u0026quot;}, {\u0026quot;%-+1.2abc\u0026quot;, \u0026quot;[%+-1.2a]bc\u0026quot;}, {\u0026quot;%-1.2abc\u0026quot;, \u0026quot;[%-1.2a]bc\u0026quot;}, } func TestFlagParser(t *testing.T) { var flagprinter flagPrinter for _, tt := range flagtests { t.Run(tt.in, func(t *testing.T) { s := Sprintf(tt.in, \u0026amp;flagprinter) if s != tt.out { t.Errorf(\u0026quot;got %q, want %q\u0026quot;, s, tt.out) } }) } } 但程执行结果和预期不符的时候使用 t.Errorf 输出即可,还有一种选项是 t.Fatalf,后者会在有错误的时候立刻停止测试用例,而前者会跑完所有的用例,推荐第一种。还可以使测试并行执行:\npackage main import ( \u0026quot;testing\u0026quot; ) func TestTLog(t *testing.T) { t.Parallel() // marks TLog as capable of running in parallel with other tests tests := []struct { name string }{ {\u0026quot;test 1\u0026quot;}, {\u0026quot;test 2\u0026quot;}, {\u0026quot;test 3\u0026quot;}, {\u0026quot;test 4\u0026quot;}, } for _, tt := range tests { tt := tt // NOTE: https://github.com/golang/go/wiki/CommonMistakes#using-goroutines-on-loop-iterator-variables t.Run(tt.name, func(t *testing.T) { t.Parallel() // marks each test case as capable of running in parallel with each other t.Log(tt.name) }) } } 上面需要注意一个点,那就是在遍历测试的需要重新赋值,tt := tt,这点非常重要,在 parallel 执行的时候会启动 goroutines 去执行测试代码,如果这时候还是使用原来的 tt 的话每次遍历执行的值都指向了一个地址,会导致很多测试用例被漏掉,更详细的可以参考上面的链接。\nSeparate Your Go Tests with Build Tags 在之前 c++ 代码中,可以根据定义的宏来决定某段代码是否执行,之前一直以为 golang 中是没有这个功能的,后来才发现是我孤陋寡闻了,golang 已经提供了 Build Tags 的功能了。\nBuild Tags build tags 就是在 .go 源文件的顶部提供单行注释来告诉编译器在执行 go build 的时候是否要处理这个文件。下面这个文件就只是在有 GOOS=linux 环境变量的时候才会去编译。\n// +build linux package mypackage ... 这个 build tag 需要尽可能的放到文件的顶部,并且需要在下方有个空行。这个 tags 同样可以用 ! 来表示否定。 // +build !linux 将会表示在非 linux 环境下被编译。tag 同样支持多个条件判断,如果是在一行的表示 或 的逻辑,如果是分成两行则表示 与 的逻辑。\n// +build linux darwin // +build amd64 package mypackage ... 上述就表示了会在 linux/amd64 和 darwin/amd64 的环境中被编译。\nSeparating Tests 上面简单的描述了下 Build Tags,那么我们就可以利用这个特性来跑不同类型的测试用例了。\n我们在跑测试用例的时候可能会有 integration 和 unit 的例子,我们下面列出两个例子怎么去区分他们。\nmyfile_test.go:\npackage mypackage import \u0026quot;testing\u0026quot; ... myfile_integration_test.go:\n// +build integration package mypackage import \u0026quot;testing\u0026quot; ... 当我们去执行 go test 的时候,就只有 myfile_test.go 文件的用例被执行了,如果想让 myfile_integration_test.go 中的测试用例也被执行,就需要提供一个 tags 参数,即go test --tags=integration。\n这里还有点小问题,就是在执行 go test --tags=integration 的时候,myfile_test.go 中的用例也会被执行,如果你不想他被执行的话,就是按照如下更改:\n// +build !integration package mypackage import \u0026quot;testing\u0026quot; ... Put your tests in a different package 正常来说一个 go 目录下只允许有一个包名,如果存在两个报名的话会有报错,但是却又特例:那就是 _tes.go 文件。\n当你想测试外部接口的时候,同时排除内部接口的干扰,这个就非常合适了,当测试文件定义了一个新的报名,调用这个文件就相当于是从外部调用。例子如下:\nfile.go:\npackage file func Open() { ... } file_test.go:\npackage file_test import ( \u0026quot;xxx/file\u0026quot; ) func TestOpen() { file.Open() } Reference https://github.com/golang/go/wiki/TableDrivenTests https://medium.com/@matryer/5-simple-tips-and-tricks-for-writing-unit-tests-in-golang-619653f90742 https://mickey.dev/posts/go-build-tags-testing ","id":2,"section":"posts","summary":"\u003cp\u003egolang unit test\u003c/p\u003e","tags":["go","unittest"],"title":"unit test","uri":"https://whalecold.github.io/2019/12/%E5%8D%95%E5%85%83%E6%B5%8B%E8%AF%95/","year":"2019"},{"content":"brief\n进入 docker 的 network namespace docker 的网络隔离用了 linux 的 namespace,这里就不多做阐述了。现在正常的生产环境中的镜像为了尽量的轻,可能不会去安装额外的无用的程序,比如 netstat, curl, wget 等工具,但是有时候需要去排查网络问题进去容器的时候发现没有这些工具又很麻烦,下面这个方式就是在主机上直接进入容器的 network namespace 去进行排查。\n假设你有一个 webserver 服务跑在容器上,你现在容器所在的主机上:\n 找到容器的 container id. docker ps | grep webserver 显示如下 从上图中可以知道容器的 id, 然后通过这个 id 拿到 pid. docker inspect ${container_id} --format='{{.State.Pid}}' 显示如下 找到 pid 后就可以直接进入 network namespace 了 nsenter -t ${pid} -n 这时候就进入了容器的 network namesapce 了,使用 ifconfig 可以看到当前的网卡信息 ","id":3,"section":"posts","summary":"\u003cp\u003ebrief\u003c/p\u003e","tags":["docker","network"],"title":"docker 笔记","uri":"https://whalecold.github.io/2019/12/docker%E7%AC%94%E8%AE%B0/","year":"2019"},{"content":"留个坑 以后更吧 哈哈哈哈哈哈\n","id":4,"section":"posts","summary":"\u003cp\u003e留个坑 以后更吧 哈哈哈哈哈哈\u003c/p\u003e","tags":["color"],"title":"HSL 学习笔记","uri":"https://whalecold.github.io/2019/11/hsl%E5%AD%A6%E4%B9%A0%E7%AC%94%E8%AE%B0/","year":"2019"},{"content":"许多年以后,面对 goland 编辑器,我准会想起找到 bug 的那个遥远的下午。\n起因 这是个历史遗留问题了,从 2 年前这个组件创建到现在。但是 Deployment 会自动拉起 OOM 的 Pod, 所以也不影响使用,直到最近开始加强了对组件的监控,才发现这个问题,于是这个锅就到了我的头上。\n排查 问题确认 开始还是肉眼看代码,但是作为一个陈年老 bug 当然不可能这么容易的被我发现,所以第一步肯定是失败了。接着借用了 golang 的 pprof 工具,发现大部分内存都卡在了 kubernetes 一个库的调用上,即如下代码:\nvar queue workqueue.RateLimitingInterface func enqueue(rk *key) { queue.AddRateLimited(rk) } 到这里还是比较懵逼,后面去看下了其他组件 queue.RateLimitingInterface 的用法,发现这里不应该调用 queue.AddRateLimited, 而是应该使用 queue.Add。把这个地方改了之后重新去跑了一段时间去看内存,发现内存确实稳定了,不再继续增长了。\n问题分析 那么为什么 queue.RateLimitingInterface 会导致 OOM 呢,这里先找到了最佳实践,即 sample-controller 和 controller-runtime,以及一个 issue, 发现正确的用法是这样的:\n The rule of thumb is: use AddRateLimited when you're retrying after an error, use Add when you're reacting to a change. For retry-able errors you'll want to do increasing backoff between consecutive attempts on the same key (with a ceiling, of course).\n 整理了一个关系图:\n而导致 bug 的这个地方在一开始就使用了 queue.AddRateLimited,这个函数会带来 latency,但是仅仅是有点延迟但也能处理的,不应该会有 OOM 的情况发生,但是重新的去看 queue.RateLimitingInterface 这个 interface,\ntype RateLimitingInterface interface { DelayingInterface // AddRateLimited adds an item to the workqueue after the rate limiter says it's ok AddRateLimited(item interface{}) // Forget indicates that an item is finished being retried. Doesn't matter whether it's for perm failing // or for success, we'll stop the rate limiter from tracking it. This only clears the `rateLimiter`, you // still have to call `Done` on the queue. Forget(item interface{}) // NumRequeues returns back how many times the item was requeued NumRequeues(item interface{}) int } 你就会发现这个还有个 function Forget, 这个 function 是用来清理 rateLimiter 的,而使用的地方始终没有去调用这个 function。接下来再去去分析了下 queue.AddRateLimited 的实现,发现这个函数实际调用的又是 q.DelayingInterface.AddAfter(item, q.rateLimiter.When(item)), AddAfter 的代码如下:\n// AddAfter adds the given item to the work queue after the given delay func (q *delayingType) AddAfter(item interface{}, duration time.Duration) { // don't add if we're already shutting down if q.ShuttingDown() { return } q.metrics.retry() // immediately add things with no delay if duration \u0026lt;= 0 { q.Add(item) return } select { case \u0026lt;-q.stopCh: // unblock if ShutDown() is called case q.waitingForAddCh \u0026lt;- \u0026amp;waitFor{data: item, readyAt: q.clock.Now().Add(duration)}: } } 这里会根据传入的 duration 来决定是立刻去处理这个 item 还是延迟 duration 的时候后去处理,所以这里还是要看下 q.rateLimiter.When(item) 的实现:\nfunc (r *ItemExponentialFailureRateLimiter) When(item interface{}) time.Duration { r.failuresLock.Lock() defer r.failuresLock.Unlock() exp := r.failures[item] r.failures[item] = r.failures[item] + 1 // The backoff is capped such that 'calculated' value never overflows. backoff := float64(r.baseDelay.Nanoseconds()) * math.Pow(2, float64(exp)) if backoff \u0026gt; math.MaxInt64 { return r.maxDelay } calculated := time.Duration(backoff) if calculated \u0026gt; r.maxDelay { return r.maxDelay } return calculated } 看到这里大概的原因就找到了,每次调用 AddRateLimited 的时候对应的 item 的 failures 就会加 1,这样每次的 backoff 就会指数级变大,但是程序里面又没有调用 Forget 去清理 failures, 所以随着 AddRateLimited 的调用,item 被存在内存中的时间也就越久,就像一个流入大于流出的水池,一直在注水缺没有去消耗水。\n","id":5,"section":"posts","summary":"\u003cp\u003e许多年以后,面对 \u003ccode\u003egoland\u003c/code\u003e 编辑器,我准会想起找到 bug 的那个遥远的下午。\u003c/p\u003e","tags":["golang","kubernetes"],"title":"k8s oom 排查记录(一)","uri":"https://whalecold.github.io/2019/11/k8s-oom-%E6%8E%92%E6%9F%A5%E8%AE%B0%E5%BD%95%E4%B8%80/","year":"2019"},{"content":"guild of self signature cert\n域名证书 生成 CA 自签证书 需要修改 openssl.cnf (在目录 / usr/local/etc/openssl 下面) 配置文件 需要加上以下配置\n[v3_ca] subjectKeyIdentifier=hash authorityKeyIdentifier=keyid:always,issuer basicConstraints = CA:true 然后把配置文件拷贝到当前目录下\n# 创建 CA 私钥 openssl genrsa -out ca.key 2048 # ⽣生成 CA 的⾃自签名证书 openssl req -new -x509 -days 365 -extensions v3_ca -key ca.key -out ca.crt -config ./openssl.cnf -sha256 自签名,生成私有证书 多域名证书 #编辑 openssl 配置 #mac 下面 openssl.cnf 应该在下面这个目录 /usr/local/etc/openssl/ 拷贝到当前目录 $ cp /usr/local/etc/openssl/openssl.cnf . # 主要修改如下 注意下面的 DNS.1 后面跟着的就是你想要添加的域名 根据需要修改 [req] req_extensions = v3_req # 这行默认注释关着的 把注释删掉 # 下面配置是新增的 [v3_req] basicConstraints = CA:FALSE keyUsage = nonRepudiation, digitalSignature, keyEncipherment subjectAltName = @alt_names [alt_names] DNS.1 = dashboard.mritd.me DNS.2 = xxx2.mritd. ### 一个证书可以支持多个域名 DNS.3 以此类推 自己定义 # 生成私钥 $ openssl genrsa -out ssl.key 2048 # 对私钥进行加密 openssl rsa -in ssl.key -des3 -out encrypted.key # 私钥生成证书请求(根据需求选择加密私钥或者非加密私钥) $ openssl req -new -key ssl.key -out ssl.csr -config openssl.cnf -sha256 # 用 ca 证书给证书请求签证 $ openssl x509 -req -in ssl.csr -CA ca.crt -CAkey ca.key -CAcreateserial -out ssl.crt -days 365 -extensions v3_req -extfile openssl.cnf -sha256 注意:在执行最后一条命令的时候出现选项 Common Name (e.g. server FQDN or YOUR name) [] 的时候,填上上述 DNS.* 中的一个域名作为主域名 普通证书 # 生成私钥 $ openssl genrsa -out ssl.key 2048 # 对私钥进行加密 $ openssl rsa -in ssl.key -des3 -out encrypted.key # 私钥生成证书请求(根据需求选择加密私钥或者非加密私钥) $ openssl req -new -key ssl.key -out ssl.csr -sha256 # 用 ca 证书给证书请求签证 $ openssl x509 -req -in ssl.csr -CA ca.crt -CAkey ca.key -CAcreateserial -out ssl.crt -days 365 -sha256 注意 在执行最后一条命令的时候出现选项 Common Name (e.g. server FQDN or YOUR name) [] 的时候,填上你需要的域名 要加上 -sha256 后缀 否则平台会因为 加密复杂度不够上传不了 ","id":6,"section":"posts","summary":"\u003cp\u003eguild of self signature cert\u003c/p\u003e","tags":["ssl","security"],"title":"自签证书","uri":"https://whalecold.github.io/2018/12/%E8%87%AA%E7%AD%BE%E8%AF%81%E4%B9%A6/","year":"2018"},{"content":"shadowsocks simple guild\n一 服务器安装 shadowsocks 服务器安装 shadowsocks 的教程网上挺多的,这里就不多介绍了,下面这个链接是 github, github1 上的,然后最好在服务器上开启bbr 加速,教程链接。\n二 安装 shadowscoks 客户端 这里用的是 mac 的客户端 shadowsocks-X,可以直接在 github 的 release 下载客户端。还有个客户端的版本是 shadowsocks-NG,可以支持本地的终端 http 和 https 的代理,但是在我本子上不能用,所以就直接 pass 掉了,然后用了 privoxy 去做终端的代理,下面会具体介绍他。关于客户端的配置应该也挺简单的,不详细介绍啦。\n三 privoxy 支持终端 http 代理 3.1 安装 brew install privoxy\n 配置 privoxy 配置 vi /usr/local/etc/privoxy/config\n 将 listen-address 默认的 8118 端口改成你想要的,我这里就不做改动了。\nlisten-address 127.0.0.1:8118 增加一行, 代表把所有匹配 / 的请求 (也就是所有请求),以 sock5 协议转发到 127.0.0.1:1080, 最后一个. 代表不转发到 http 代理\nforward-socks5 / 127.0.0.1:1080 . forward 192.168.*.*/ . forward 10.*.*.*/ . forward 127.*.*.*/ . forward hello.test.com/ . 这里解释下上面的配置:第一行就是把所有的代理请求以 sock5 协议转发到 127.0.0.1:1080。然后我为了方便直接在在全局变量里面把 http 代理设置成 privoxy 的地址了。\nexport http_proxy=http://127.0.0.1:8118 export https_proxy=http://127.0.0.1:8118 这样会导致一个问题,就是一些本地或者是公司局域网的请求也会全部代理到 ss 服务器上,你就会发现这些请求失败了。所以下面的几行就是表示这些地址不做转发。\n 启动 privoxy, brew services start privoxy\n 记得把上面代理的命令加到文件 ~/.zshrc 或者 ~/.bashrc 文件里面去,然后执行 source ~/.zshrc 或者 source ~/.bashrc,看具体用户使用的终端而定。\n 这样终端的代理就好了,当你使用 git、go get 之类的命令再也不用担心被墙了。\n3.2 docker 代理 现在会有写小伙伴会在自己的本子上安装 docker,但是在拉去镜像的时候是不是也经常遇到拉去失败的情况,有了 privoxy 和 ss 就能解决这个问题啦。打开 docker 应用的 preferences 选项,选中 proxies ,下面有 http 和 https 代理选项,把 http://127.0.0.1:8118 填入就可以很顺利的拉到被墙的镜像了。\n3.3 minikube 代理 在本地安装 minikube 之后也会遇到被墙的情况。\n基本思路也是和上面的一样,去走 http 代理,所以问题是怎么让 minikube 走代理呢。\n步骤如下:\n 修改 minikube 的配置文件 ~/.minikube/machines/minikube/config.json\n \u0026quot;HostOptions\u0026quot;: { \u0026quot;Driver\u0026quot;: \u0026quot;\u0026quot;, \u0026quot;Memory\u0026quot;: 0, \u0026quot;Disk\u0026quot;: 0, \u0026quot;EngineOptions\u0026quot;: { \u0026quot;ArbitraryFlags\u0026quot;: null, \u0026quot;Dns\u0026quot;: null, \u0026quot;GraphDir\u0026quot;: \u0026quot;\u0026quot;, \u0026quot;Env\u0026quot;: [ \u0026quot;HTTP_PROXY=http://192.168.1.58:8118\u0026quot;, \u0026quot;HTTPS_PROXY=http://192.168.1.58:8118\u0026quot; ], \u0026quot;Ipv6\u0026quot;: false, \u0026quot;InsecureRegistry\u0026quot;: [ \u0026quot;10.96.0.0/12\u0026quot; ], \u0026quot;Labels\u0026quot;: null, \u0026quot;LogLevel\u0026quot;: \u0026quot;\u0026quot;, \u0026quot;StorageDriver\u0026quot;: \u0026quot;\u0026quot;, \u0026quot;SelinuxEnabled\u0026quot;: false, \u0026quot;TlsVerify\u0026quot;: false, \u0026quot;RegistryMirror\u0026quot;: [ \u0026quot;https://registry.docker-cn.com\u0026quot; ], \u0026quot;InstallURL\u0026quot;: \u0026quot;\u0026quot; }, 需要修改的 json 配置就是 HostOptions.EngineOptions.Env,加上当前的代理。ip 即位本机 ip,然后重启 minikube。\n 这里需要注意的一个问题就是需要改下 privoxy 的 listen-address 配置。之前的是这样的\nlisten-address 127.0.0.1:8118 这监听的本机的应用,对于别的虚拟机访问会被拒绝。所以要进行如下修改:\nlisten-address 0.0.0.0:8118 四 其他 app 科学上网 mac 本子还有不少其他 app,这部分不支持 http 代理,比如邮件之类的,这个怎么办呢,就需要 proxifier 这个应用了。\n这个应该也蛮简单的,教程在 这里, 暂时就先不整理啦。\n五 分布式 到这里为止基本上就实现了 mac 全局翻墙了,但是抱着折腾的心态,最后再加个 nginx 代理吧。\nnginx 支持了 tcp 层的转发,所以也可以支持 socket5,步骤如下:\n brew install nginx\n 修改配置文件 /usr/local/etc/nginx/nginx.conf,加入以下配置:\nstream{ upstream shadows { server shadowsocks.com max_fails=3 fail_timeout=10s; } server{ listen 10080; proxy_connect_timeout 20s; proxy_timeout 5m; proxy_pass shadows; } } 其中 shadowsocks.com 就是实际的服务器地址。\n brew services start nginx\n 把客户端的地址对应修改下\n ","id":7,"section":"posts","summary":"\u003cp\u003eshadowsocks simple guild\u003c/p\u003e","tags":["mac","shadowsocks"],"title":"科学上网","uri":"https://whalecold.github.io/2018/10/%E7%A7%91%E5%AD%A6%E4%B8%8A%E7%BD%91/","year":"2018"},{"content":"一个简单的 kubernetes 集群搭建教程\nkubernetes v1.10.6 搭建手记 这里主要是跟着这篇 博客 做的,但是这篇博客是基于 1.8.2 的版本来的,和 1.10.6 有不少区别,所以再做个记录。\n Build Enviroment Build Etcd Cluster Install cfssl build ca install etcd Build flannel network build master components build kube-apiserver build kube-controller-manager build kube-scheduler build kubectl build node components install kubelet install kube-proxy build plug-in install coredns install heapster Build Enviroment 为了方便搭建目前只是用了两台虚拟机测试,ip 分别是 192.168.21.8 和 192.168.21.9, os 是 centos 7.4\n组件版本 Kubernetes 1.10.6 Docker 17.03.1-ce (最新的对 container-selinux 版本有要求) Etcd 3.3.9 Flanneld TLS 认证通信(所有组件,如 etcd、kubernetes master 和 node) kubedns、dashboard、heapster 等插件 自己先设置好环境变量 后面的署将会使用到下面的变量,定义如下(根据自己的机器、网络修改):\n #TLS Bootstrapping 使用的 Token,可以使用命令 head -c 16 /dev/urandom | od -An -t x \u0026gt; tr -d ' ' 生成 BOOTSTRAP_TOKEN=\u0026quot;8981b594122ebed7596f1d3b69c78223\u0026quot; #建议使用未用的网段来定义服务网段和 Pod 网段 #服务网段 (Service CIDR),部署前路由不可达,部署后集群内部使用 IP:Port 可达 SERVICE_CIDR=\u0026quot;10.254.0.0/16\u0026quot; #Pod 网段 (Cluster CIDR),部署前路由不可达,部署后路由可达 (flanneld 保证) CLUSTER_CIDR=\u0026quot;172.30.0.0/16\u0026quot; #服务端口范围 (NodePort Range) NODE_PORT_RANGE=\u0026quot;30000-32766\u0026quot; #etcd 集群服务地址列表 这里暂时先只有一台 ETCD_ENDPOINTS=\u0026quot;https://192.168.31.8:2379\u0026quot; #flanneld 网络配置前缀 FLANNEL_ETCD_PREFIX=\u0026quot;/kubernetes/network\u0026quot; #kubernetes 服务 IP(预先分配,一般为 SERVICE_CIDR 中的第一个 IP) CLUSTER_KUBERNETES_SVC_IP=\u0026quot;10.254.0.1\u0026quot; #集群 DNS 服务 IP(从 SERVICE_CIDR 中预先分配) CLUSTER_DNS_SVC_IP=\u0026quot;10.254.0.2\u0026quot; #集群 DNS 域名 CLUSTER_DNS_DOMAIN=\u0026quot;cluster.local.\u0026quot; #MASTER API Server 地址 MASTER_URL=\u0026quot;k8s-api.virtual.local\u0026quot; 保存为 env.sh, 赋加可执行权限 chmod +x env.sh, 执行 mkdir -p /usr/k8s/bin, 将这个目录添加到系统可执行目录里面,export PATH=/usr/k8s/bin:$PATH, 为了方便可以把这个命令添加到 ~/.bashrc 里面, 把脚本添加到上面的目录中。\nBuild Etcd Cluster Install Cfssl kubernetes 系统需要使用 TLS 证书对通信加密, 这里使用 cfssl 生成证书。\n $ wget https://pkg.cfssl.org/R1.2/cfssl_linux-amd64 $ chmod +x cfssl_linux-amd64 $ mv cfssl_linux-amd64 /usr/k8s/bin/cfssl $ wget https://pkg.cfssl.org/R1.2/cfssljson_linux-amd64 $ chmod +x cfssljson_linux-amd64 $ mv cfssljson_linux-amd64 /usr/k8s/bin/cfssljson $ wget https://pkg.cfssl.org/R1.2/cfssl-certinfo_linux-amd64 $ chmod +x cfssl-certinfo_linux-amd64 $ mv cfssl-certinfo_linux-amd64 /usr/k8s/bin/cfssl-certinfo $ mkdir ssl \u0026amp;\u0026amp; cd ssl $ cfssl print-defaults config \u0026gt; config.json $ cfssl print-defaults csr \u0026gt; csr.json Build Ca 修改上面创建的 config.json 文件为 ca-config.json:\n\u0026gt; { \u0026gt; \u0026quot;signing\u0026quot;: { \u0026gt; \u0026quot;default\u0026quot;: { \u0026gt; \u0026quot;expiry\u0026quot;: \u0026quot;87600h\u0026quot; \u0026gt; }, \u0026gt; \u0026quot;profiles\u0026quot;: { \u0026gt; \u0026quot;kubernetes\u0026quot;: { \u0026gt; \u0026quot;expiry\u0026quot;: \u0026quot;87600h\u0026quot;, \u0026gt; \u0026quot;usages\u0026quot;: [ \u0026gt; \u0026quot;signing\u0026quot;, \u0026gt; \u0026quot;key encipherment\u0026quot;, \u0026gt; \u0026quot;server auth\u0026quot;, \u0026gt; \u0026quot;client auth\u0026quot; \u0026gt; ] \u0026gt; } \u0026gt; } \u0026gt; } \u0026gt; } config.json:可以定义多个 profiles,分别指定不同的过期时间、使用场景等参数;后续在签名证书时使用某个 profile。 signing: 表示该证书可用于签名其它证书;生成的 ca.pem 证书中 CA=TRUE。 server auth: 表示 client 可以用该 CA 对 server 提供的证书进行校验。 client auth: 表示 server 可以用该 CA 对 client 提供的证书进行验证。 修改 CA 证书签名请求为 ca-csr.json:\n{ \u0026quot;CN\u0026quot;: \u0026quot;kubernetes\u0026quot;, \u0026quot;key\u0026quot;: { \u0026quot;algo\u0026quot;: \u0026quot;rsa\u0026quot;, \u0026quot;size\u0026quot;: 2048 }, \u0026quot;names\u0026quot;: [ { \u0026quot;C\u0026quot;: \u0026quot;CN\u0026quot;, \u0026quot;L\u0026quot;: \u0026quot;BeiJing\u0026quot;, \u0026quot;ST\u0026quot;: \u0026quot;BeiJing\u0026quot;, \u0026quot;O\u0026quot;: \u0026quot;k8s\u0026quot;, \u0026quot;OU\u0026quot;: \u0026quot;System\u0026quot; } ] } 生成 CA 证书和私钥:\ncfssl gencert -initca ca-csr.json | cfssljson -bare ca ls ca* ca-config.json ca.csr ca-csr.json ca-key.pem ca.pem 将生成的 CA 证书、密钥文件、配置文件拷贝到所有机器的 / etc/kubernetes/ssl 目录下面:\nmkdir -p /etc/kubernetes/ssl cp ca* /etc/kubernetes/ssl Install Etcd 只是测试用 所以只部署一个节点 192.168.21.8,命名是 etcd01:\n定义环境变量 $ export NODE_NAME=etcd01 # 当前部署的机器名称 (随便定义,只要能区分不同机器即可) $ export NODE_IP=192.168.21.8 # 当前部署的机器 IP $ export NODE_IPS=\u0026quot;192.168.21.8\u0026quot; # etcd 集群所有机器 IP $ # etcd 集群间通信的 IP 和端口 $ export ETCD_NODES=etcd01=https://192.168.21.8:2380 $ # 导入用到的其它全局变量:ETCD_ENDPOINTS、FLANNEL_ETCD_PREFIX、CLUSTER_CIDR $ source /usr/k8s/bin/env.sh 下载 etcd 二进制文件 自己去 github 去下载找到对应版本就好了\n创建 TLS 密钥和证书 创建 etcd 证书签名请求:\n$ cat \u0026gt; etcd-csr.json \u0026lt;\u0026lt;EOF { \u0026quot;CN\u0026quot;: \u0026quot;etcd\u0026quot;, \u0026quot;hosts\u0026quot;: [ \u0026quot;127.0.0.1\u0026quot;, \u0026quot;${NODE_IP}\u0026quot; ], \u0026quot;key\u0026quot;: { \u0026quot;algo\u0026quot;: \u0026quot;rsa\u0026quot;, \u0026quot;size\u0026quot;: 2048 }, \u0026quot;names\u0026quot;: [ { \u0026quot;C\u0026quot;: \u0026quot;CN\u0026quot;, \u0026quot;ST\u0026quot;: \u0026quot;BeiJing\u0026quot;, \u0026quot;L\u0026quot;: \u0026quot;BeiJing\u0026quot;, \u0026quot;O\u0026quot;: \u0026quot;k8s\u0026quot;, \u0026quot;OU\u0026quot;: \u0026quot;System\u0026quot; } ] } EOF NODE_IP 即上面的全局变量 生成 etcd 证书和私钥:\n$ cfssl gencert -ca=/etc/kubernetes/ssl/ca.pem \\ -ca-key=/etc/kubernetes/ssl/ca-key.pem \\ -config=/etc/kubernetes/ssl/ca-config.json \\ -profile=kubernetes etcd-csr.json | cfssljson -bare etcd $ ls etcd* etcd.csr etcd-csr.json etcd-key.pem etcd.pem $ mkdir -p /etc/etcd/ssl $ mv etcd*.pem /etc/etcd/ssl/ 创建 etcd 的 systemd unit 文件\n$ mkdir -p /var/lib/etcd # 必须要先创建工作目录 $ cat \u0026gt; etcd.service \u0026lt;\u0026lt;EOF [Unit] Description=Etcd Server After=network.target After=network-online.target Wants=network-online.target Documentation=https://github.com/coreos [Service] Type=notify WorkingDirectory=/var/lib/etcd/ ExecStart=/usr/k8s/bin/etcd \\\\ --name=${NODE_NAME} \\\\ --cert-file=/etc/etcd/ssl/etcd.pem \\\\ --key-file=/etc/etcd/ssl/etcd-key.pem \\\\ --peer-cert-file=/etc/etcd/ssl/etcd.pem \\\\ --peer-key-file=/etc/etcd/ssl/etcd-key.pem \\\\ --trusted-ca-file=/etc/kubernetes/ssl/ca.pem \\\\ --peer-trusted-ca-file=/etc/kubernetes/ssl/ca.pem \\\\ --initial-advertise-peer-urls=https://${NODE_IP}:2380 \\\\ --listen-peer-urls=https://${NODE_IP}:2380 \\\\ --listen-client-urls=https://${NODE_IP}:2379,http://127.0.0.1:2379 \\\\ --advertise-client-urls=https://${NODE_IP}:2379 \\\\ --initial-cluster-token=etcd-cluster-0 \\\\ --initial-cluster=${ETCD_NODES} \\\\ --initial-cluster-state=new \\\\ --data-dir=/var/lib/etcd Restart=on-failure RestartSec=5 LimitNOFILE=65536 [Install] WantedBy=multi-user.target EOF 启动 etcd 服务\nmv etcd.service /etc/systemd/system/ systemctl daemon-reload systemctl enable etcd systemctl start etcd systemctl status etcd 验证\nfor ip in ${NODE_IPS}; do ETCDCTL_API=3 /usr/k8s/bin/etcdctl \\ --endpoints=https://${ip}:2379 \\ --cacert=/etc/kubernetes/ssl/ca.pem \\ --cert=/etc/etcd/ssl/etcd.pem \\ --key=/etc/etcd/ssl/etcd-key.pem \\ endpoint health; done 结果\nhttps://192.168.21.8:2379 is healthy: successfully committed proposal: took = 2.132456ms etcd 到这里就已经搭建好了,下面开始搭建 flanneld 网络。\nBuild Flannel Network 需要在所有的 node 节点安装\n 环境变量 $ export NODE_IP=192.168.21.8 # 当前部署节点的 IP # 导入全局变量 $ source /usr/k8s/bin/env.sh 创建 TLS 密钥和证书 etcd 集群启用了双向 TLS 认证,所以需要为 flanneld 指定与 etcd 集群通信的 CA 和密钥。\n创建 flanneld 证书签名请求:\n$ cat \u0026gt; flanneld-csr.json \u0026lt;\u0026lt;EOF { \u0026quot;CN\u0026quot;: \u0026quot;flanneld\u0026quot;, \u0026quot;hosts\u0026quot;: [], \u0026quot;key\u0026quot;: { \u0026quot;algo\u0026quot;: \u0026quot;rsa\u0026quot;, \u0026quot;size\u0026quot;: 2048 }, \u0026quot;names\u0026quot;: [ { \u0026quot;C\u0026quot;: \u0026quot;CN\u0026quot;, \u0026quot;ST\u0026quot;: \u0026quot;BeiJing\u0026quot;, \u0026quot;L\u0026quot;: \u0026quot;BeiJing\u0026quot;, \u0026quot;O\u0026quot;: \u0026quot;k8s\u0026quot;, \u0026quot;OU\u0026quot;: \u0026quot;System\u0026quot; } ] } EOF 生成 flanneld 证书和私钥:\n$ cfssl gencert -ca=/etc/kubernetes/ssl/ca.pem \\ -ca-key=/etc/kubernetes/ssl/ca-key.pem \\ -config=/etc/kubernetes/ssl/ca-config.json \\ -profile=kubernetes flanneld-csr.json | cfssljson -bare flanneld $ ls flanneld* flanneld.csr flanneld-csr.json flanneld-key.pem flanneld.pem $ sudo mkdir -p /etc/flanneld/ssl $ sudo mv flanneld*.pem /etc/flanneld/ssl 向 etcd 写入集群 Pod 网段信息 该步骤只需在第一次部署 Flannel 网络时执行,后续在其他节点上部署 Flanneld 时无需再写入该信息\n $ etcdctl \\ --endpoints=${ETCD_ENDPOINTS} \\ --ca-file=/etc/kubernetes/ssl/ca.pem \\ --cert-file=/etc/flanneld/ssl/flanneld.pem \\ --key-file=/etc/flanneld/ssl/flanneld-key.pem \\ set ${FLANNEL_ETCD_PREFIX}/config '{\u0026quot;Network\u0026quot;:\u0026quot;'${CLUSTER_CIDR}'\u0026quot;,\u0026quot;SubnetLen\u0026quot;: 24,\u0026quot;Backend\u0026quot;: {\u0026quot;Type\u0026quot;:\u0026quot;vxlan\u0026quot;}}' # 得到如下反馈信息 {\u0026quot;Network\u0026quot;:\u0026quot;172.30.0.0/16\u0026quot;, \u0026quot;SubnetLen\u0026quot;: 24, \u0026quot;Backend\u0026quot;: {\u0026quot;Type\u0026quot;: \u0026quot;vxlan\u0026quot;}} 写入的 Pod 网段 (${CLUSTER_CIDR},172.30.0.0/16) 必须与 kube-controller-manager 的 \u0026ndash;cluster-cidr 选项值一致; 安装和配置 flanneld 先去 flanneld release 页面下载最新版的 flanneld 二进制文件。\n$ mkdir flannel $ wget https://github.com/coreos/flannel/releases/download/v0.9.0/flannel-v0.9.0-linux-amd64.tar.gz $ tar -xzvf flannel-v0.9.0-linux-amd64.tar.gz -C flannel $ cp flannel/{flanneld,mk-docker-opts.sh} /usr/k8s/bin 创建 flanneld 的 systemd unit 文件\n$ cat \u0026gt; flanneld.service \u0026lt;\u0026lt; EOF [Unit] Description=Flanneld overlay address etcd agent After=network.target After=network-online.target Wants=network-online.target After=etcd.service Before=docker.service [Service] Type=notify ExecStart=/usr/k8s/bin/flanneld \\\\ -etcd-cafile=/etc/kubernetes/ssl/ca.pem \\\\ -etcd-certfile=/etc/flanneld/ssl/flanneld.pem \\\\ -etcd-keyfile=/etc/flanneld/ssl/flanneld-key.pem \\\\ -etcd-endpoints=${ETCD_ENDPOINTS} \\\\ -etcd-prefix=${FLANNEL_ETCD_PREFIX} ExecStartPost=/usr/k8s/bin/mk-docker-opts.sh -k DOCKER_NETWORK_OPTIONS -d /run/flannel/docker Restart=on-failure [Install] WantedBy=multi-user.target RequiredBy=docker.service EOF 启动 flanneld\n$ cp flanneld.service /etc/systemd/system/ $ systemctl daemon-reload $ systemctl enable flanneld $ systemctl start flanneld $ systemctl status flanneld 检查服务命令:ifconfig flannel.1\n检查分配给各 flanneld 的 Pod 网段信息\n$ # 查看集群 Pod 网段 (/16) $ etcdctl \\ --endpoints=${ETCD_ENDPOINTS} \\ --ca-file=/etc/kubernetes/ssl/ca.pem \\ --cert-file=/etc/flanneld/ssl/flanneld.pem \\ --key-file=/etc/flanneld/ssl/flanneld-key.pem \\ get ${FLANNEL_ETCD_PREFIX}/config {\u0026quot;Network\u0026quot;: \u0026quot;172.30.0.0/16\u0026quot;, \u0026quot;SubnetLen\u0026quot;: 24, \u0026quot;Backend\u0026quot;: { \u0026quot;Type\u0026quot;: \u0026quot;vxlan\u0026quot;} } $ # 查看已分配的 Pod 子网段列表 (/24) $ etcdctl \\ --endpoints=${ETCD_ENDPOINTS} \\ --ca-file=/etc/kubernetes/ssl/ca.pem \\ --cert-file=/etc/flanneld/ssl/flanneld.pem \\ --key-file=/etc/flanneld/ssl/flanneld-key.pem \\ ls ${FLANNEL_ETCD_PREFIX}/subnets /kubernetes/network/subnets/172.30.77.0-24 $ # 查看某一 Pod 网段对应的 flanneld 进程监听的 IP 和网络参数 $ etcdctl \\ --endpoints=${ETCD_ENDPOINTS} \\ --ca-file=/etc/kubernetes/ssl/ca.pem \\ --cert-file=/etc/flanneld/ssl/flanneld.pem \\ --key-file=/etc/flanneld/ssl/flanneld-key.pem \\ get ${FLANNEL_ETCD_PREFIX}/subnets/172.30.77.0-24 {\u0026quot;PublicIP\u0026quot;:\u0026quot;192.168.1.137\u0026quot;,\u0026quot;BackendType\u0026quot;:\u0026quot;vxlan\u0026quot;,\u0026quot;BackendData\u0026quot;:{\u0026quot;VtepMAC\u0026quot;:\u0026quot;62:fc:03:83:1b:2b\u0026quot;}} 确保各节点间 Pod 网段能互联互通 在各个节点部署完 Flanneld 后,查看已分配的 Pod 子网段列表:\n$ etcdctl \\ --endpoints=${ETCD_ENDPOINTS} \\ --ca-file=/etc/kubernetes/ssl/ca.pem \\ --cert-file=/etc/flanneld/ssl/flanneld.pem \\ --key-file=/etc/flanneld/ssl/flanneld-key.pem \\ ls ${FLANNEL_ETCD_PREFIX}/subnets /kubernetes/network/subnets/172.30.54.0-24 /kubernetes/network/subnets/172.30.74.0-24 Build Master Components kubernetes master 节点包含的组件有:\n kube-apiserver kube-scheduler kube-controller-manager 这三个组件需要在一台机器上面。master 节点与 node 节点上的 Pods 通过 Pod 网络通信,所以需要在 master 节点上部署 Flannel 网络。\n环境变量 $ export NODE_IP=192.168.21.8 # 当前部署的 master 机器 IP $ source /usr/k8s/bin/env.sh 下载对应版本的二进制文件: 在 kubernetes changelog 页面下载最新版本的文件:\n$ wget https://storage.googleapis.com/kubernetes-release/release/v1.10.6/kubernetes-server-linux-amd64.tar.gz $ tar -xzvf kubernetes-server-linux-amd64.tar.gz 然后将里面的二进制文件拷贝到 /usr/k8s/bin 目录里面\n创建 kubernetes 证书 创建 kubernetes 证书签名请求:\n$ cat \u0026gt; kubernetes-csr.json \u0026lt;\u0026lt;EOF { \u0026quot;CN\u0026quot;: \u0026quot;kubernetes\u0026quot;, \u0026quot;hosts\u0026quot;: [ \u0026quot;127.0.0.1\u0026quot;, \u0026quot;${NODE_IP}\u0026quot;, \u0026quot;${MASTER_URL}\u0026quot;, \u0026quot;${CLUSTER_KUBERNETES_SVC_IP}\u0026quot;, \u0026quot;kubernetes\u0026quot;, \u0026quot;kubernetes.default\u0026quot;, \u0026quot;kubernetes.default.svc\u0026quot;, \u0026quot;kubernetes.default.svc.cluster\u0026quot;, \u0026quot;kubernetes.default.svc.cluster.local\u0026quot; ], \u0026quot;key\u0026quot;: { \u0026quot;algo\u0026quot;: \u0026quot;rsa\u0026quot;, \u0026quot;size\u0026quot;: 2048 }, \u0026quot;names\u0026quot;: [ { \u0026quot;C\u0026quot;: \u0026quot;CN\u0026quot;, \u0026quot;ST\u0026quot;: \u0026quot;BeiJing\u0026quot;, \u0026quot;L\u0026quot;: \u0026quot;BeiJing\u0026quot;, \u0026quot;O\u0026quot;: \u0026quot;k8s\u0026quot;, \u0026quot;OU\u0026quot;: \u0026quot;System\u0026quot; } ] } EOF 生成 kubernetes 证书和私钥:\n$ cfssl gencert -ca=/etc/kubernetes/ssl/ca.pem \\ -ca-key=/etc/kubernetes/ssl/ca-key.pem \\ -config=/etc/kubernetes/ssl/ca-config.json \\ -profile=kubernetes kubernetes-csr.json | cfssljson -bare kubernetes $ ls kubernetes* kubernetes.csr kubernetes-csr.json kubernetes-key.pem kubernetes.pem $ mkdir -p /etc/kubernetes/ssl/ $ mv kubernetes*.pem /etc/kubernetes/ssl/ Build Kube-apiserver 创建 kube-apiserver 使用的客户端 token 文件 kubelet 首次启动时向 kube-apiserver 发送 TLS Bootstrapping 请求,kube-apiserver 验证请求中的 token 是否与它配置的 token.csv 一致,如果一致则自动为 kubelet 生成证书和密钥。\n$ # 导入的 environment.sh 文件定义了 BOOTSTRAP_TOKEN 变量 $ cat \u0026gt; token.csv \u0026lt;\u0026lt;EOF ${BOOTSTRAP_TOKEN},kubelet-bootstrap,10001,\u0026quot;system:kubelet-bootstrap\u0026quot; EOF $ mv token.csv /etc/kubernetes/ 创建 kube-apiserver 的 systemd unit 文件 在创建之前需要先生成一个日志策略文件 (/etc/kubernetes/audit-policy.yaml):\napiVersion: audit.k8s.io/v1beta1 # This is required. kind: Policy # Don't generate audit events for all requests in RequestReceived stage. omitStages: - \u0026quot;RequestReceived\u0026quot; rules: # Log pod changes at RequestResponse level - level: RequestResponse resources: - group: \u0026quot;\u0026quot; # Resource \u0026quot;pods\u0026quot; doesn't match requests to any subresource of pods, # which is consistent with the RBAC policy. resources: [\u0026quot;pods\u0026quot;] # Log \u0026quot;pods/log\u0026quot;, \u0026quot;pods/status\u0026quot; at Metadata level - level: Metadata resources: - group: \u0026quot;\u0026quot; resources: [\u0026quot;pods/log\u0026quot;, \u0026quot;pods/status\u0026quot;] # Don't log requests to a configmap called\u0026quot;controller-leader\u0026quot; - level: None resources: - group: \u0026quot;\u0026quot; resources: [\u0026quot;configmaps\u0026quot;] resourceNames: [\u0026quot;controller-leader\u0026quot;] # Don't log watch requests by the\u0026quot;system:kube-proxy\u0026quot; on endpoints or services - level: None users: [\u0026quot;system:kube-proxy\u0026quot;] verbs: [\u0026quot;watch\u0026quot;] resources: - group: \u0026quot;\u0026quot; # core API group resources: [\u0026quot;endpoints\u0026quot;, \u0026quot;services\u0026quot;] # Don't log authenticated requests to certain non-resource URL paths. - level: None userGroups: [\u0026quot;system:authenticated\u0026quot;] nonResourceURLs: - \u0026quot;/api*\u0026quot; # Wildcard matching. - \u0026quot;/version\u0026quot; # Log the request body of configmap changes in kube-system. - level: Request resources: - group: \u0026quot;\u0026quot; # core API group resources: [\u0026quot;configmaps\u0026quot;] # This rule only applies to resources in the \u0026quot;kube-system\u0026quot; namespace. # The empty string \u0026quot;\u0026quot; can be used to select non-namespaced resources. namespaces: [\u0026quot;kube-system\u0026quot;] # Log configmap and secret changes in all other namespaces at the Metadata level. - level: Metadata resources: - group: \u0026quot;\u0026quot; # core API group resources: [\u0026quot;secrets\u0026quot;, \u0026quot;configmaps\u0026quot;] # Log all other resources in core and extensions at the Request level. - level: Request resources: - group: \u0026quot;\u0026quot; # core API group - group: \u0026quot;extensions\u0026quot; # Version of group should NOT be included. # A catch-all rule to log all other requests at the Metadata level. - level: Metadata # Long-running requests like watches that fall under this rule will not # generate an audit event in RequestReceived. omitStages: - \u0026quot;RequestReceived\u0026quot; 审查日志的相关配置可以查看 文档了解\n下面是 unit 文件:\n$ cat \u0026gt; kube-apiserver.service \u0026lt;\u0026lt;EOF [Unit] Description=Kubernetes API Server Documentation=https://github.com/GoogleCloudPlatform/kubernetes After=network.target [Service] ExecStart=/usr/k8s/bin/kube-apiserver \\\\ --admission-control=NamespaceLifecycle,LimitRanger,ServiceAccount,DefaultStorageClass,ResourceQuota,NodeRestriction \\\\ --advertise-address=${NODE_IP} \\\\ --bind-address=0.0.0.0 \\\\ --insecure-bind-address=${NODE_IP} \\\\ --authorization-mode=Node,RBAC \\\\ --runtime-config=rbac.authorization.k8s.io/v1alpha1 \\\\ --kubelet-https=true \\\\ --token-auth-file=/etc/kubernetes/token.csv \\\\ --service-cluster-ip-range=${SERVICE_CIDR} \\\\ --service-node-port-range=${NODE_PORT_RANGE} \\\\ --tls-cert-file=/etc/kubernetes/ssl/kubernetes.pem \\\\ --tls-private-key-file=/etc/kubernetes/ssl/kubernetes-key.pem \\\\ --client-ca-file=/etc/kubernetes/ssl/ca.pem \\\\ --service-account-key-file=/etc/kubernetes/ssl/ca-key.pem \\\\ --etcd-cafile=/etc/kubernetes/ssl/ca.pem \\\\ --etcd-certfile=/etc/kubernetes/ssl/kubernetes.pem \\\\ --etcd-keyfile=/etc/kubernetes/ssl/kubernetes-key.pem \\\\ --etcd-servers=${ETCD_ENDPOINTS} \\\\ --enable-swagger-ui=true \\\\ --allow-privileged=true \\\\ --apiserver-count=2 \\\\ --audit-log-maxage=30 \\\\ --audit-log-maxbackup=3 \\\\ --audit-log-maxsize=100 \\\\ --audit-log-path=/var/lib/audit.log \\\\ --audit-policy-file=/etc/kubernetes/audit-policy.yaml \\\\ --event-ttl=1h \\\\ --logtostderr=true \\\\ --v=6 Restart=on-failure RestartSec=5 Type=notify LimitNOFILE=65536 [Install] WantedBy=multi-user.target EOF 启动 kube-apiserver $ cp kube-apiserver.service /etc/systemd/system/ $ systemctl daemon-reload $ systemctl enable kube-apiserver $ systemctl start kube-apiserver $ systemctl status kube-apiserver Build Kube-controller-manager 创建 kube-controller-manager 的 systemd unit 文件 $ cat \u0026gt; kube-controller-manager.service \u0026lt;\u0026lt;EOF [Unit] Description=Kubernetes Controller Manager Documentation=https://github.com/GoogleCloudPlatform/kubernetes [Service] ExecStart=/usr/k8s/bin/kube-controller-manager \\\\ --address=127.0.0.1 \\\\ --master=http://${MASTER_URL}:8080 \\\\ --allocate-node-cidrs=true \\\\ --service-cluster-ip-range=${SERVICE_CIDR} \\\\ --cluster-cidr=${CLUSTER_CIDR} \\\\ --cluster-name=kubernetes \\\\ --cluster-signing-cert-file=/etc/kubernetes/ssl/ca.pem \\\\ --cluster-signing-key-file=/etc/kubernetes/ssl/ca-key.pem \\\\ --service-account-private-key-file=/etc/kubernetes/ssl/ca-key.pem \\\\ --root-ca-file=/etc/kubernetes/ssl/ca.pem \\\\ --leader-elect=true \\\\ --v=2 Restart=on-failure RestartSec=5 [Install] WantedBy=multi-user.target EOF 启动 kube-controller-manager $ cp kube-controller-manager.service /etc/systemd/system/ $ systemctl daemon-reload $ systemctl enable kube-controller-manager $ systemctl start kube-controller-manager $ systemctl status kube-controller-manager Build Kube-scheduler 创建 kube-scheduler 的 systemd unit 文件 $ cat \u0026gt; kube-scheduler.service \u0026lt;\u0026lt;EOF [Unit] Description=Kubernetes Scheduler Documentation=https://github.com/GoogleCloudPlatform/kubernetes [Service] ExecStart=/usr/k8s/bin/kube-scheduler \\\\ --address=127.0.0.1 \\\\ --master=http://${MASTER_URL}:8080 \\\\ --leader-elect=true \\\\ --v=2 Restart=on-failure RestartSec=5 [Install] WantedBy=multi-user.target EOF 启动 kube-scheduler $ cp kube-scheduler.service /etc/systemd/system/ $ systemctl daemon-reload $ systemctl enable kube-scheduler $ systemctl start kube-scheduler $ systemctl status kube-scheduler Build Kubectl kubectl 默认从 ~/.kube/config 配置文件中获取访问 kube-apiserver 地址、证书、用户名等信息,需要正确配置该文件才能正常使用 kubectl 命令。\n环境变量 $ source /usr/k8s/bin/env.sh $ export KUBE_APISERVER=\u0026quot;https://${MASTER_URL}:6443\u0026quot; 下载 kubectl $ wget https://dl.k8s.io/v1.10.6/kubernetes-client-linux-amd64.tar.gz # 如果服务器上下载不下来,可以想办法下载到本地,然后 scp 上去即可 $ tar -xzvf kubernetes-client-linux-amd64.tar.gz $ cp kubernetes/client/bin/kube* /usr/k8s/bin/ $ chmod +x /usr/k8s/bin/kube* 创建 admin 证书 kubectl 与 kube-apiserver 的安全端口通信,需要为安全通信提供 TLS 证书和密钥。创建 admin 证书签名请求:\n$ cat \u0026gt; admin-csr.json \u0026lt;\u0026lt;EOF { \u0026quot;CN\u0026quot;: \u0026quot;admin\u0026quot;, \u0026quot;hosts\u0026quot;: [], \u0026quot;key\u0026quot;: { \u0026quot;algo\u0026quot;: \u0026quot;rsa\u0026quot;, \u0026quot;size\u0026quot;: 2048 }, \u0026quot;names\u0026quot;: [ { \u0026quot;C\u0026quot;: \u0026quot;CN\u0026quot;, \u0026quot;ST\u0026quot;: \u0026quot;BeiJing\u0026quot;, \u0026quot;L\u0026quot;: \u0026quot;BeiJing\u0026quot;, \u0026quot;O\u0026quot;: \u0026quot;system:masters\u0026quot;, \u0026quot;OU\u0026quot;: \u0026quot;System\u0026quot; } ] } EOF 生成 admin 证书和私钥:\n$ cfssl gencert -ca=/etc/kubernetes/ssl/ca.pem \\ -ca-key=/etc/kubernetes/ssl/ca-key.pem \\ -config=/etc/kubernetes/ssl/ca-config.json \\ -profile=kubernetes admin-csr.json | cfssljson -bare admin $ ls admin admin.csr admin-csr.json admin-key.pem admin.pem $ sudo mv admin*.pem /etc/kubernetes/ssl/ 创建 kubectl kubeconfig 文件 # 设置集群参数 $ kubectl config set-cluster kubernetes \\ --certificate-authority=/etc/kubernetes/ssl/ca.pem \\ --embed-certs=true \\ --server=${KUBE_APISERVER} # 设置客户端认证参数 $ kubectl config set-credentials admin \\ --client-certificate=/etc/kubernetes/ssl/admin.pem \\ --embed-certs=true \\ --client-key=/etc/kubernetes/ssl/admin-key.pem \\ --token=${BOOTSTRAP_TOKEN} # 设置上下文参数 $ kubectl config set-context kubernetes \\ --cluster=kubernetes \\ --user=admin # 设置默认上下文 $ kubectl config use-context kubernetes 将 ~/.kube/config 文件拷贝到运行 kubectl 命令的机器的 ~/.kube/ 目录下去。\n完成后验证下 master 节点:\n# kubectl get componentstatuses NAME STATUS MESSAGE ERROR controller-manager Healthy ok scheduler Healthy ok etcd-0 Healthy {\u0026quot;health\u0026quot;:\u0026quot;true\u0026quot;} Build Node Components kubernetes Node 节点包含如下组件:\n flanneld docker kubelet kube-proxy 环境变量 # source /usr/k8s/bin/env.sh # export KUBE_APISERVER=\u0026quot;https://${MASTER_URL}\u0026quot; // 如果你没有安装 `haproxy` 的话,还是需要使用 6443 端口的哦 # export NODE_IP=192.168.21.9 # 当前部署的节点 IP 按照上面的步骤安装配置好 flanneld\n开启路由转发 修改 /etc/sysctl.conf 文件,添加下面的规则:\nnet.ipv4.ip_forward=1 net.bridge.bridge-nf-call-iptables=1 net.bridge.bridge-nf-call-ip6tables=1 执行下面的命令立即生效:\n$ sysctl -p 配置 docker 你可以用二进制或 yum install 的方式来安装 docker,然后修改 docker 的 systemd unit 文件:\n$ cat /usr/lib/systemd/system/docker.service # 用 systemctl status docker 命令可查看 unit 文件路径 [Unit] Description=Docker Application Container Engine Documentation=https://docs.docker.com After=network-online.target firewalld.service Wants=network-online.target [Service] Type=notify # the default is not to use systemd for cgroups because the delegate issues still # exists and systemd currently does not support the cgroup feature set required # for containers run by docker EnvironmentFile=-/run/flannel/docker ExecStart=/usr/bin/dockerd --log-level=info $DOCKER_NETWORK_OPTIONS ExecReload=/bin/kill -s HUP $MAINPID # Having non-zero Limit*s causes performance problems due to accounting overhead # in the kernel. We recommend using cgroups to do container-local accounting. LimitNOFILE=infinity LimitNPROC=infinity LimitCORE=infinity # Uncomment TasksMax if your systemd version supports it. # Only systemd 226 and above support this version. #TasksMax=infinity TimeoutStartSec=0 # set delegate yes so that systemd does not reset the cgroups of docker containers Delegate=yes # kill only the docker process, not all processes in the cgroup KillMode=process # restart the docker process if it exits prematurely Restart=on-failure StartLimitBurst=3 StartLimitInterval=60s [Install] WantedBy=multi-user.target 注意关闭防火墙 使用方便点。。然后可以配置国内的 docker 镜像源\n启动 docker $ sudo systemctl daemon-reload $ sudo systemctl stop firewalld $ sudo systemctl disable firewalld $ sudo iptables -F \u0026amp;\u0026amp; sudo iptables -X \u0026amp;\u0026amp; sudo iptables -F -t nat \u0026amp;\u0026amp; sudo iptables -X -t nat $ sudo systemctl enable docker $ sudo systemctl start docker Install Kubelet kubelet 启动时向 kube-apiserver 发送 TLS bootstrapping 请求,需要先将 bootstrap token 文件中的 kubelet-bootstrap 用户赋予 system:node-bootstrapper 角色,然后 kubelet 才有权限创建认证请求 (certificatesigningrequests):\n kubelet 就是运行在 Node 节点上的,所以这一步安装是在所有的 Node 节点上,如果你想把你的 Master 也当做 Node 节点的话,当然也可以在 Master 节点上安装的。\n kubectl create clusterrolebinding kubelet-bootstrap --clusterrole=system:node-bootstrapper --user=kubelet-bootstrap --user=kubelet-bootstrap 是文件 /etc/kubernetes/token.csv 中指定的用户名,同时也写入了文件 /etc/kubernetes/bootstrap.kubeconfig 创建 kubelet bootstapping kubeconfig 文件 $ # 设置集群参数 $ kubectl config set-cluster kubernetes \\ --certificate-authority=/etc/kubernetes/ssl/ca.pem \\ --embed-certs=true \\ --server=${KUBE_APISERVER} \\ --kubeconfig=bootstrap.kubeconfig $ # 设置客户端认证参数 $ kubectl config set-credentials kubelet-bootstrap \\ --token=${BOOTSTRAP_TOKEN} \\ --kubeconfig=bootstrap.kubeconfig $ # 设置上下文参数 $ kubectl config set-context default \\ --cluster=kubernetes \\ --user=kubelet-bootstrap \\ --kubeconfig=bootstrap.kubeconfig $ # 设置默认上下文 $ kubectl config use-context default --kubeconfig=bootstrap.kubeconfig $ mv bootstrap.kubeconfig /etc/kubernetes/ 创建 kubelet 的 systemd unit 文件 注意:pod-infra-container-image 这个配置项后面加镜像源 主要是考虑到 k8s 官方源国内访问不了, 需要单独去配置 我这里用的是私有源\n$ sudo mkdir /var/lib/kubelet # 必须先创建工作目录 $ cat \u0026gt; kubelet.service \u0026lt;\u0026lt;EOF [Unit] Description=Kubernetes Kubelet Documentation=https://github.com/GoogleCloudPlatform/kubernetes After=docker.service Requires=docker.service [Service] WorkingDirectory=/var/lib/kubelet ExecStart=/usr/k8s/bin/kubelet \\\\ --fail-swap-on=false \\\\ --cgroup-driver=cgroupfs \\\\ --address=${NODE_IP} \\\\ --hostname-override=${NODE_IP} \\\\ --experimental-bootstrap-kubeconfig=/etc/kubernetes/bootstrap.kubeconfig \\\\ --kubeconfig=/etc/kubernetes/kubelet.kubeconfig \\\\ --pod-infra-container-image=gcr.io/google_containers/pause-amd64:3.1 \\ --cert-dir=/etc/kubernetes/ssl \\\\ --cluster-dns=${CLUSTER_DNS_SVC_IP} \\\\ --cluster-domain=${CLUSTER_DNS_DOMAIN} \\\\ --hairpin-mode promiscuous-bridge \\\\ --allow-privileged=true \\\\ --serialize-image-pulls=false \\\\ --logtostderr=true \\\\ --v=2 Restart=on-failure RestartSec=5 [Install] WantedBy=multi-user.target EOF 启动 kubelet $ sudo cp kubelet.service /etc/systemd/system/kubelet.service $ sudo systemctl daemon-reload $ sudo systemctl enable kubelet $ sudo systemctl start kubelet $ systemctl status kubelet 通过 kubelet 的 TLS 证书请求 $ kubectl get csr NAME AGE REQUESTOR CONDITION node-csr--k3G2G1EoM4h9w1FuJRjJjfbIPNxa551A8TZfW9dG-g 2m kubelet-bootstrap Pending $ kubectl get nodes No resources found. 通过 CSR 请求:\n$ kubectl certificate approve node-csr--k3G2G1EoM4h9w1FuJRjJjfbIPNxa551A8TZfW9dG-g certificatesigningrequest \u0026quot;node-csr--k3G2G1EoM4h9w1FuJRjJjfbIPNxa551A8TZfW9dG-g\u0026quot; approved $ kubectl get nodes NAME STATUS ROLES AGE VERSION 192.168.21.9 Ready \u0026lt;none\u0026gt; 48s v1.10.6 自动生成了 kubelet kubeconfig 文件和公私钥:\n$ ls -l /etc/kubernetes/kubelet.kubeconfig -rw------- 1 root root 2280 Nov 7 10:26 /etc/kubernetes/kubelet.kubeconfig $ ls -l /etc/kubernetes/ssl/kubelet* -rw-r--r-- 1 root root 1046 Nov 7 10:26 /etc/kubernetes/ssl/kubelet-client.crt -rw------- 1 root root 227 Nov 7 10:22 /etc/kubernetes/ssl/kubelet-client.key -rw-r--r-- 1 root root 1115 Nov 7 10:16 /etc/kubernetes/ssl/kubelet.crt -rw------- 1 root root 1675 Nov 7 10:16 /etc/kubernetes/ssl/kubelet.key Install Kube-proxy 创建 kube-proxy 证书签名请求: $ cat \u0026gt; kube-proxy-csr.json \u0026lt;\u0026lt;EOF { \u0026quot;CN\u0026quot;: \u0026quot;system:kube-proxy\u0026quot;, \u0026quot;hosts\u0026quot;: [], \u0026quot;key\u0026quot;: { \u0026quot;algo\u0026quot;: \u0026quot;rsa\u0026quot;, \u0026quot;size\u0026quot;: 2048 }, \u0026quot;names\u0026quot;: [ { \u0026quot;C\u0026quot;: \u0026quot;CN\u0026quot;, \u0026quot;ST\u0026quot;: \u0026quot;BeiJing\u0026quot;, \u0026quot;L\u0026quot;: \u0026quot;BeiJing\u0026quot;, \u0026quot;O\u0026quot;: \u0026quot;k8s\u0026quot;, \u0026quot;OU\u0026quot;: \u0026quot;System\u0026quot; } ] } EOF 生成 kube-proxy 客户端证书和私钥 $ cfssl gencert -ca=/etc/kubernetes/ssl/ca.pem \\ -ca-key=/etc/kubernetes/ssl/ca-key.pem \\ -config=/etc/kubernetes/ssl/ca-config.json \\ -profile=kubernetes kube-proxy-csr.json | cfssljson -bare kube-proxy $ ls kube-proxy* kube-proxy.csr kube-proxy-csr.json kube-proxy-key.pem kube-proxy.pem $ mv kube-proxy*.pem /etc/kubernetes/ssl/ 创建 kube-proxy kubeconfig 文件 $ # 设置集群参数 $ kubectl config set-cluster kubernetes \\ --certificate-authority=/etc/kubernetes/ssl/ca.pem \\ --embed-certs=true \\ --server=${KUBE_APISERVER} \\ --kubeconfig=kube-proxy.kubeconfig $ # 设置客户端认证参数 $ kubectl config set-credentials kube-proxy \\ --client-certificate=/etc/kubernetes/ssl/kube-proxy.pem \\ --client-key=/etc/kubernetes/ssl/kube-proxy-key.pem \\ --embed-certs=true \\ --kubeconfig=kube-proxy.kubeconfig $ # 设置上下文参数 $ kubectl config set-context default \\ --cluster=kubernetes \\ --user=kube-proxy \\ --kubeconfig=kube-proxy.kubeconfig $ # 设置默认上下文 $ kubectl config use-context default --kubeconfig=kube-proxy.kubeconfig $ mv kube-proxy.kubeconfig /etc/kubernetes/ 创建 kube-proxy 的 systemd unit 文件 $ sudo mkdir -p /var/lib/kube-proxy # 必须先创建工作目录 $ cat \u0026gt; kube-proxy.service \u0026lt;\u0026lt;EOF [Unit] Description=Kubernetes Kube-Proxy Server Documentation=https://github.com/GoogleCloudPlatform/kubernetes After=network.target [Service] WorkingDirectory=/var/lib/kube-proxy ExecStart=/usr/k8s/bin/kube-proxy \\\\ --bind-address=${NODE_IP} \\\\ --hostname-override=${NODE_IP} \\\\ --cluster-cidr=${SERVICE_CIDR} \\\\ --kubeconfig=/etc/kubernetes/kube-proxy.kubeconfig \\\\ --logtostderr=true \\\\ --v=2 Restart=on-failure RestartSec=5 LimitNOFILE=65536 [Install] WantedBy=multi-user.target EOF 启动 kube-proxy $ sudo cp kube-proxy.service /etc/systemd/system/ $ sudo systemctl daemon-reload $ sudo systemctl enable kube-proxy $ sudo systemctl start kube-proxy $ systemctl status kube-proxy 验证集群功能 定义 yaml 文件:(将下面内容保存为:nginx-ds.yaml)\napiVersion: v1 kind: Service metadata: name: nginx-ds labels: app: nginx-ds spec: type: NodePort selector: app: nginx-ds ports: - name: http port: 80 targetPort: 80 --- apiVersion: extensions/v1beta1 kind: DaemonSet metadata: name: nginx-ds labels: addonmanager.kubernetes.io/mode: Reconcile spec: template: metadata: labels: app: nginx-ds spec: containers: - name: my-nginx image: nginx:1.7.9 ports: - containerPort: 80 创建 Pod 和服务:\n$ kubectl create -f nginx-ds.yml service \u0026quot;nginx-ds\u0026quot; created daemonset \u0026quot;nginx-ds\u0026quot; created 执行下面的命令查看 Pod 和 SVC:\n$ kubectl get pods -o wide NAME READY STATUS RESTARTS AGE IP NODE nginx-ds-f29zt 1/1 Running 0 23m 172.30.54.2 192.168.21.9 $ kubectl get svc NAME TYPE CLUSTER-IP EXTERNAL-IP PORT(S) AGE nginx-ds NodePort 10.0.0.169 \u0026lt;none\u0026gt; 80:30265/TCP 24m Build Plug-in Install Coredns CoreDNS 给出了标准的 deployment 配置,如下\n coredns.yaml.sed apiVersion: v1 kind: ServiceAccount metadata: name: coredns namespace: kube-system --- apiVersion: rbac.authorization.k8s.io/v1beta1 kind: ClusterRole metadata: labels: kubernetes.io/bootstrapping: rbac-defaults name: system:coredns rules: - apiGroups: - \u0026quot;\u0026quot; resources: - endpoints - services - pods - namespaces verbs: - list - watch --- apiVersion: rbac.authorization.k8s.io/v1beta1 kind: ClusterRoleBinding metadata: annotations: rbac.authorization.kubernetes.io/autoupdate: \u0026quot;true\u0026quot; labels: kubernetes.io/bootstrapping: rbac-defaults name: system:coredns roleRef: apiGroup: rbac.authorization.k8s.io kind: ClusterRole name: system:coredns subjects: - kind: ServiceAccount name: coredns namespace: kube-system --- apiVersion: v1 kind: ConfigMap metadata: name: coredns namespace: kube-system data: Corefile: | .:53 { errors health kubernetes CLUSTER_DOMAIN REVERSE_CIDRS { pods insecure upstream fallthrough in-addr.arpa ip6.arpa } prometheus :9153 proxy . /etc/resolv.conf cache 30 } --- apiVersion: extensions/v1beta1 kind: Deployment metadata: name: coredns namespace: kube-system labels: k8s-app: kube-dns kubernetes.io/name: \u0026quot;CoreDNS\u0026quot; spec: replicas: 2 strategy: type: RollingUpdate rollingUpdate: maxUnavailable: 1 selector: matchLabels: k8s-app: kube-dns template: metadata: labels: k8s-app: kube-dns spec: serviceAccountName: coredns tolerations: - key: \u0026quot;CriticalAddonsOnly\u0026quot; operator: \u0026quot;Exists\u0026quot; containers: - name: coredns image: coredns/coredns:1.1.1 imagePullPolicy: IfNotPresent args: [\u0026quot;-conf\u0026quot;, \u0026quot;/etc/coredns/Corefile\u0026quot;] volumeMounts: - name: config-volume mountPath: /etc/coredns ports: - containerPort: 53 name: dns protocol: UDP - containerPort: 53 name: dns-tcp protocol: TCP - containerPort: 9153 name: metrics protocol: TCP livenessProbe: httpGet: path: /health port: 8080 scheme: HTTP initialDelaySeconds: 60 timeoutSeconds: 5 successThreshold: 1 failureThreshold: 5 dnsPolicy: Default volumes: - name: config-volume configMap: name: coredns items: - key: Corefile path: Corefile --- apiVersion: v1 kind: Service metadata: name: kube-dns namespace: kube-system annotations: prometheus.io/scrape: \u0026quot;true\u0026quot; labels: k8s-app: kube-dns kubernetes.io/cluster-service: \u0026quot;true\u0026quot; kubernetes.io/name: \u0026quot;CoreDNS\u0026quot; spec: selector: k8s-app: kube-dns clusterIP: CLUSTER_DNS_IP ports: - name: dns port: 53 protocol: UDP - name: dns-tcp port: 53 protocol: TCP 这个文件在所在 github 地址:https://github.com/kubernetes/kubernetes/tree/release-1.10/cluster/addons/dns\n需要对这个文件做一些改动:\n 61 行 kubernetes $DNS_DOMAIN in-addr.arpa ip6.arpa 中的 $DNS_DOMAIN 改为 cluster.local 153 行 clusterIP: $DNS_SERVER_IP 中 $DNS_SERVER_IP 改为全局变量 CLUSTER_DNS_SVC_IP 的值 创建 dns kubectl create -f coredns.yaml Install Heapster yaml 创建一下就可以了\nkubectl create -f https://raw.githubusercontent.com/kubernetes/heapster/master/deploy/kube-config/influxdb/grafana.yaml kubectl create -f https://raw.githubusercontent.com/kubernetes/heapster/master/deploy/kube-config/influxdb/heapster.yaml kubectl create -f https://raw.githubusercontent.com/kubernetes/heapster/master/deploy/kube-config/influxdb/influxdb.yaml kubectl create -f https://raw.githubusercontent.com/kubernetes/heapster/master/deploy/kube-config/rbac/heapster-rbac.yaml 在国内可能会失败,因为访问不到 k8s 镜像源。这样需要把 yaml 下载到本地, 然后修改 image 后面的选项。\n","id":8,"section":"posts","summary":"\u003cp\u003e一个简单的 kubernetes 集群搭建教程\u003c/p\u003e","tags":["golang","kubernetes"],"title":"kubernetes 搭建","uri":"https://whalecold.github.io/2018/09/kubernetes%E6%90%AD%E5%BB%BA/","year":"2018"},{"content":"shell operation record\nshell note 查看进程启动时间: ps -A -opid,stime,etime,args sort 命令 grep key file | grep -w 88 | awk -F '[()]' '{map[$4]+=$12}END{for(i in map){print i\u0026quot; \u0026quot;map[i]}}' | sort -un -k2 操作数据库 result=mysql ${config} -e \u0026quot;${sql}\u0026quot; 字符串操作 取数组操作 arr=(${out}) eg: out=12:23:34:45:56 arr=(${out//:/}) //12 23 34 45 56 数组 len=${\\#arr[@]} // 数组长度 ${arr[0]} 取字符串长度 string=abc12342341 // 等号二边不要有空格 echo ${\\#string} // 结果 11 expr length $string // 结果 11 expr \u0026quot;$string\u0026quot; : \u0026quot;.\\*\u0026quot; // 结果 11 分号二边要有空格, 这里的: 根 match 的用法差不多 字符串所在位置 expr index $string '123' // 结果 4 字符串对应的下标是从 0 开始的 字符串截取 echo ${string:4} //2342341 从第 4 位开始截取后面所有字符串 echo ${string:3:3} //123 从第 3 位开始截取后面 3 位 echo ${string:3:6} //123423 从第 3 位开始截取后面 6 位 echo ${string: -4} //2341 :右边有空格 截取后 4 位 echo ${string:(-4)} //2341 同上 expr substr $string 3 3 //123 从第 3 位开始截取后面 3 位 从字符串开头到子串的最大长度 expr match $string 'abc.\\*3' // 结果 9 匹配显示内容 expr match $string '\\\\([a-c]\\*[0-9]\\*\\\\)' //abc12342341 expr $string : '\\\\([a-c]\\*[0-9]\\\\)' //abc1 expr $string : '.\\*\\\\([0-9][0-9][0-9]\\\\)' //341 显示括号中匹配的内容 截取不匹配的内容 echo ${string\\#a\\*3} //42341 从 $string 左边开始,去掉最短匹配子串 echo ${string\\#c\\*3} //abc12342341 这样什么也没有匹配到 echo ${string\\#\\*c1\\*3} //42341 从 $string 左边开始,去掉最短匹配子串 echo ${string\\#\\#a\\*3} //41 从 $string 左边开始,去掉最长匹配子串 echo ${string%3\\*1} //abc12342 从 $string 右边开始,去掉最短匹配子串 echo ${string%%3\\*1} //abc12 从 $string 右边开始,去掉最长匹配子串 匹配并且替换 echo ${string/23/bb} //abc1bb42341 替换一次 echo ${string//23/bb} //abc1bb4bb41 双斜杠替换所有匹配 echo ${string/\\#abc/bb} //bb12342341 \\# 以什么开头来匹配,根 php 中的 ^ 有点像 echo ${string/%41/bb} //abc123423bb % 以什么结尾来匹配,根 php 中的 $ 有点像 ","id":9,"section":"posts","summary":"\u003cp\u003eshell operation record\u003c/p\u003e","tags":["shell","linux"],"title":"shell note","uri":"https://whalecold.github.io/2017/12/shell-note/","year":"2017"}],"tags":[{"title":"cgroup","uri":"https://whalecold.github.io/tags/cgroup/"},{"title":"color","uri":"https://whalecold.github.io/tags/color/"},{"title":"docker","uri":"https://whalecold.github.io/tags/docker/"},{"title":"go","uri":"https://whalecold.github.io/tags/go/"},{"title":"golang","uri":"https://whalecold.github.io/tags/golang/"},{"title":"kubernetes","uri":"https://whalecold.github.io/tags/kubernetes/"},{"title":"linux","uri":"https://whalecold.github.io/tags/linux/"},{"title":"mac","uri":"https://whalecold.github.io/tags/mac/"},{"title":"network","uri":"https://whalecold.github.io/tags/network/"},{"title":"security","uri":"https://whalecold.github.io/tags/security/"},{"title":"shadowsocks","uri":"https://whalecold.github.io/tags/shadowsocks/"},{"title":"shell","uri":"https://whalecold.github.io/tags/shell/"},{"title":"ssl","uri":"https://whalecold.github.io/tags/ssl/"},{"title":"unittest","uri":"https://whalecold.github.io/tags/unittest/"}]}