寻找利用Kubernetes进行开发的最佳实践

这篇文章是关于Recruit Lifestyle Advent Calendar 2017的第9篇文章。

在CET项目中,我负责AB测试的提案、分析和开发等工作。晚上好,我是@mihirat。

AWS也推出了托管服务,Kubernetes的热潮正在兴起。顺便说一句,我去年写的入门文章即将获得200个赞,这让我感到惊讶。现在回过头来看,里面有一些有点可疑的解释…

我想总结一下我们团队目前正在使用的k8s的临时最佳实践。

前提 – qian2 ti2 (premise, condition)

    • GKEでの話

 

    弊社の某サービスの一部ページのwebサーバーをk8sで運用してます

形成

组成图

advent.png

关于构成

虽然K8s中有Ingress,为什么要使用GCP的负载均衡器呢?原因有几个。

    1. 想要使用GCS进行静态内容的传递。在考虑使用CDN静态内容传递服务时,发现可以将GCS作为Load Balancer的后端bucket来使用。但如果选择使用Ingress,则无法使用这个功能,所以我选择使用LB。(后备方案将在后文提及)

为了确保服务的可用性,并在多个区域中设置集群,我希望使用k8s的Federation进行验证。然而,经过验证后得出了目前还不适合在生产环境中使用的结论。作为替代方案,我们将k8s集群挂载在Load Balancer的后面。

关于开发周围的各种各样事情

除了 LB、GCS、全局地址和防火墙规则等k8s资源之外,我们使用Terraform管理其他GCP资源。与k8s相关的其他资源,如Docker和yaml系列都集中在一个仓库里。恕我打广告,但我们参考了解决方案架构师提供的GKE最佳实践进行配置。

部署

在部署过程中,我们基本上使用kubectl从CI执行所有操作。我们使用Drone作为我们的CI工具。

流程如下:
1. 构建 Docker
2. 对 Docker 镜像进行 serverspec 或单元测试
3. 如果测试通过,将镜像推送到 Google Container Registry(GCR)
4. 使用 GCR 的镜像指定参数,执行 kubectl apply -f

一旦部署完成后,会在有关人员的slack频道中通知部署的结果。另外,我们还准备了rollback.sh等用于紧急回退的工具,以便任何T的人都可以进行处理。

各种YAML配置

使用kubectl apply -f命令更新部署时,我们可以在此过程中进行一些滚动更新的设置调整。
考虑到在某些时刻,可用的pod数量可能会极端减少,从而可能影响服务的响应能力,我们需要进行一些配置以防止这种情况的发生。

  strategy:
    type: RollingUpdate
    rollingUpdate:
      maxSurge: 10% # maximum number of Pods that can be created above the desired number of Pods
      maxUnavailable: 0% # maximum number of Pods that can be unavailable during the update process.

如果在策略部分进行这样的设置,首先将创建一个具有新的docker image的pod,并在该pod可用后删除现有的pod。
如果新创建的docker image存在问题或者创建pod时出现任何障碍,现有的pod数量不会减少,流量仍将流向现有的pod,这样可以放心。
(虽然有漏洞就没意义了,我要教训自己…)

通过将 maxSurge 设置为较小值,可以控制每次替换的数量。如果设置过大,当 nodes 的计算资源刚好满负荷时,无法创建新的 pod。
通过在创建集群时指定 –enable-autoscaling,可以避免这种情况并且可以增减 nodes 的数量,尽管可能需要一些时间。

考试

由于找不到关于k8s测试的好信息,所以我们根据需要采取了相应的措施。

首先,通过使用Dockerspec,您可以对创建的镜像运行Serverspec测试。这样就可以针对每个镜像进行测试。

作为进一步的通信测试,dockerspec可以在内部使用docker-compose,因此可以在多个容器启动的情况下运行测试。

假设有这样一个nginx例子。

  # pseudo code
  upstream backend1 {
    server  backend1:80;
  }
  upstream backend2 {
    server  backend2:80;
  }

  server {
    location /be1/ {
      proxy_pass http://backend1/;
    }
    location /be2/ {
      proxy_pass http://backend2/;
    }
  }

准备一个这样的docker-compose文件

version: '2'
services:
 frontend:
   image: asia.gcr.io/__GOOGLE_PROJECT__/frontend:latest
   volumes:
     - /var/run/docker.sock:/var/run/docker.sock
   links:
     - backend1
     - backend2
   ports:
     - 38080:80
 backend1:
   image: backend1:latest
   expose:
     - 80
 backend2:
   image: backend2:latest
   expose:
     - 80

我可以做这样的测试。


describe docker_compose("#{ENV['COMPOSE_FILE']}", wait: 5) do
  its_container(:frontend) do
    describe 'access to backend 1' do
      subject do
        command("curl http://127.0.0.1/be1/ -v")
      end
      its(:stderr) { should match /HTTP\/1.1 200 OK/ }
    end
    describe 'access to backend 2' do
      subject do
        command("curl http://127.0.0.1/be2/ -v")
      end
      its(:stderr) { should match /HTTP\/1.1 200 OK/ }
    end
  end
end

因为这只是一个模拟的通信测试,所以我认为本来应该在k8s集群上进行测试。我正在探索在CI上使用minikube等更好的测试方法。

监视

基本上,看起来Prometheus是首选。它有针对k8s的官方yaml文件,也有很多实际应用案例。它还可以对每个pod进行资源监控,对于需要详细信息的情况似乎很有用。

现在,T不再使用Prometheus,所有日志都通过stdout发送给Stackdriver,并直接流向BigQuery。

在Google BigQuery上创建一个Redash来连接,并定期从Redash中查询nginx访问日志等数据,以创建包括服务器响应时间等信息的仪表盘。
此外,如果检测到500等错误,会通过Slack与开发人员进行通知,以便能够立即通知开发人员。

未来(正在考虑中)

目前我们正在以这样的形式进行开发,但在一些结构上正在讨论改进的建议。目前的结构中,terraform和k8s的分解点有些困难,k8s的可变性部分还没有得到充分利用。

    1. 使用Fuse在Kubernetes上挂载GCS

 

    1. 在上述配置中,我想要使用后端存储桶和云CDN,但是有一种将云存储作为Kubernetes的卷进行挂载的功能。

 

    1. https://karlstoney.com/2017/03/01/fuse-mount-in-kubernetes/

 

    1. 利用Ingress

 

    与使用terraform创建L7 LB相比,我仍然希望使用Kubernetes独有的Ingress。要么放弃多区域,要么使用Federation来使用改进的Federated Ingress。

最后 | 综上所述 | 总之 | 总结

k8s的最佳实践,特别是关于测试、配置和运维等方面的信息很难找到,并且我们在摸索中陷入了这种情况。
Istio等新技术层出不穷,我们希望能够不断采纳并追求最佳实践。
期待您在评论中能够给出更好的配置建议!

bannerAds