Kubernetes:一个价格实惠的个人项目解决方案

大家好!

一月,我们终于有了期待已久的关于Kubernetes的书。 Gigi Saifan关于“掌握Kubernetes第二版”的演讲:


大约一年前,我们不敢在Kubernetes上出版一本书,因为那时该技术对于超级公司来说绝对是无力的。 但是,这种情况正在发生变化,为此,我们建议阅读Caleb Doxsey的一篇大文章,顺便说一句,他写了一关于Go语言的 。 Doxy先生的论点非常有趣,我们希望阅读它们之后,您真的想在实践中尝试Kubernetes。

我在今年年初花了几个月的时间对Kubernetes进行了深入研究:我需要一个工作项目。 Kubernetes是一种用于基础结构管理的综合技术,它“包括所有内容,甚至包括电池”。 Kubernetes解决了为大型企业开发时注定要遇到的许多问题。 但是,人们一直相信Kubernetes是一种过于复杂的技术,仅与管理大型机器集群有关。 据称,与Kubernetes一起使用时的操作负载是如此之大,以至于它在小型基础设施中使用,而该机器不会挤入数十台机器,是向大麻雀射击的大炮。
我不同意这一点。 Kubernetes也适合小型项目,如今您已经可以以每月不到5美元的价格负担自己的Kubernetes集群。

捍卫Kubernetes的一句话

下面,我将向您展示如何设置自己的Kubernetes集群,但首先尝试解释为什么在小型项目中应使用Kubernetes:

Kubernetes是彻底的

是的,乍一看,Kubernetes似乎有点多余。 获取和获取虚拟机而不将自己的应用程序配置为服务似乎更容易,为什么不呢? 选择此路径,您将必须决定一些解决方案,尤其是:

  1. 如何部署应用程序? 只是将其同步到服务器?
  2. 那依赖关系呢? 如果您使用Python或Ruby,则必须将它们安装在服务器上。 您要手动运行命令吗?
  3. 您将如何启动该应用程序? 只是在后台执行二进制文件,然后再不执行它? 这可能不太好,所以如果您将应用程序作为服务进行组织,则必须学习systemd?
  4. 当它们都具有不同的域名或http路径时,您将如何处理它们的操作? (您可能需要为此配置haproxy或nginx)
  5. 假设您已经更新了应用程序。 您将如何推出更改? 停止服务,部署代码,重新启动服务? 如何避免停机?
  6. 如果您锁定部署怎么办? 有回滚的机会吗? (Symlink目录...?此简单脚本不再显得特别简单)
  7. 您的应用程序是否使用其他服务,例如redis? 如何配置所有这些服务?

Kubernetes解决了所有这些问题。 当然,它们都可以通过其他方式解决,其中有Kubernetes更好的选择。 但是,根本不考虑所有这些并专注于应用程序开发要好得多。

Kubernetes是可靠的

一台服务器将始终崩溃。 是的,这种情况很少见,也许每年一次,但是在这样的事件发生之后,真正的头痛开始了:如何使一切恢复到工作状态。 如果您自己手动配置了整个配置,则尤其如此。 还记得上一次跑的所有队伍吗? 您还记得服务器上的工作原理吗? 我记得bashorg的一句话:
埃诺:嗯。 丢失了计算机...严重,_丢失_。 他回应,工作正常,我只是不知道他去了公寓。
bash.org/?5273
最近在我自己的博客中发生了同样的事情。 我只需要更新链接,但是我完全忘记了如何部署博客。 突然,十分钟的修复变成了整个周末的工作。

Kubernetes使用一种描述性格式,因此您始终知道应该在什么地方,什么时间,什么地方运行它。 此外,已部署系统的所有组件都更加清晰可见。 此外,在控制平面中,节点故障得到了仔细处理,炉床会自动重新分配。 当使用不保留状态的服务(例如,使用Web应用程序)时,您可能会完全忘记失败。

学习Kubernetes并不比选择困难

Kubernetes不遵循Unix模型。 它不适合工具生态系统。 他不是“只做一件事情就做得很好”的那些决定之一。 Kubernetes是解决许多问题的综合解决方案,它可以替代开发人员已经习惯的各种技巧和工具。

Kubernetes具有自己的术语,自己的工具,自己的服务器处理范例,这与传统的unix方法有很大的不同。 在这些系统上导航时,Kubernetes的许多功能似乎是随机的,过于复杂的,甚至可能是残酷的。 我认为出现这种复杂性的原因很充分,但是在这里我并不是说Kubernetes简单易懂。 我是说Kubernetes的知识足以创建和支持任何基础架构。

这并不是说任何系统管理员在UNIX中都有足够的背景知识。 例如,大学毕业后,我在Windows生态系统中工作了5年。 我可以说,我在需要处理linux的初创公司的第一份工作需要进行艰难的转型。 我不知道存储命令;我几乎不习惯在所有情况下使用命令行。 我花了一些时间来学习如何使用新平台(尽管那时我已经有了一些编程经验),但是我清楚地记得自己遭受了多少痛苦。

使用Kubernetes,您可以从头开始所有工作。 在Kubernetes中,即使没有与服务器的SSH连接,您也可以轻松配置服务。 您不必学习systemd。 不需要了解运行级别或知道使用了哪个命令: groupaddaddgroup ; 您不必学习如何处理ps或者,天哪,vim。 所有这些材料都是有用且重要的,它不会消失在任何地方。 我非常尊重能够在任何unix环境下工作的系统管理员。 但是,如果开发人员可以有效地获取所有这些资源而又不去研究管理的精妙之处,那会多么酷呢?

真的是这样吗?

 [Unit] Description=The NGINX HTTP and reverse proxy server After=syslog.target network.target remote-fs.target nss-lookup.target [Service] Type=forking PIDFile=/run/nginx.pid ExecStartPre=/usr/sbin/nginx -t ExecStart=/usr/sbin/nginx ExecReload=/usr/sbin/nginx -s reload ExecStop=/bin/kill -s QUIT $MAINPID PrivateTmp=true [Install] WantedBy=multi-user.target 

比这难得多吗?

 apiVersion: apps/v1 kind: Deployment metadata: name: my-nginx spec: selector: matchLabels: run: my-nginx replicas: 1 template: metadata: labels: run: my-nginx spec: containers: - name: my-nginx image: nginx ports: - containerPort: 80 

这仍然是一个比较好的案例。 如果您100%远程管理基础架构,则将无法提供手动服务器支持。 为此,您将需要某种工具:ansible,盐,厨师,木偶等。 自然地,为了掌握Kubernetes并有效地使用它,您需要学习很多东西,但这并不比处理替代方案困难。

Kubernetes开源

在无服务器技术迅速普及的时代,Kubernetes以其与特定供应商的独立性着称。 至少有3家受欢迎且易于管理的Kubernetes提供商(谷歌,亚马逊,微软)在可预见的将来不会消失。 也有许多公司成功地管理自己的Kubernetes集群,并且这类公司的数量每天都在成倍增长。 今天,从一开始就与Kubernetes合作对于大多数初创公司来说都是显而易见的解决方案。
Kubernetes是一个开放源代码项目,有据可查,稳定且受欢迎,并且可以在stackoverflow上尽可能详细地解决任何问题。 当然,Kubernetes有其自身的错误和技术挑战,但我向您保证:世界上有些人以令人难以置信的技能磨练Kubernetes。 他们的工作是您的收获; 在未来几年中,这项技术只会得到改进。

Kubernetes规模

与支持基础结构相关的挑战之一是:在部署小型系统时有用的技术很少能成功复制到大型系统中。 如果您只有一台服务器,将SCP二进制文件绑定到服务器,终止进程并重新启动它绝对方便。 但是,当您需要支持多台服务器并同时对其进行监视时,这样的任务可能会变得异常困难。 这就是为什么在管理这样的基础架构时没有厨师或木偶之类的工具的原因。

但是,如果您选择了错误的工具,随着时间的流逝,它可能会使您陷入困境。 突然发现,领先的主厨服务器无法应对1000台服务器的负载,蓝绿色部署不适合您的模型,并且需要数小时才能完成capistrano任务。 当基础架构达到一定规模时,您将被迫拆除已经完成的一切并重新开始。 如果您可以突破具有基础结构的永恒松鼠轮,并转向根据您的需求扩展的技术,那将有多大?

Kubernetes非常像SQL数据库。 SQL是有关数据存储和有效查询的多年艰辛课程的产物。 也许,您甚至将不需要有效的SQL数据库中提供的这些功能的十分之一。 您甚至可以依靠自己的数据库来设计效率更高的系统。 但是在绝大多数情况下,SQL数据库不仅可以满足您的所有需求,而且可以极大地扩展您快速发布现成解决方案的能力。 SQL模式和索引比基于本地文件的数据结构更易于使用,因为随着产品的发展,本地数据结构几乎肯定会过时。 但是SQL数据库很可能在任何不可避免的重构中都可以幸免。

Kubernetes也将生存。 也许您的辅助项目将永远无法发展到只能使用Kubernetes解决其问题的规模,但是Kubernetes绝对拥有解决所有问题的所有工具,并且当您使用此工具箱时,所获得的技能可能会在未来的项目中具有不可估量的价值。

建立自己的Kubernetes集群

因此,我相信在小型项目中使用Kubernetes是明智的选择,但前提是建立集群非常简单且便宜。 事实证明,两者都是可以实现的。 有Kubernetes托管的提供程序可以自己处理整个混乱,并支持Kubernetes主机的控制平面。 而且,最近在云基础架构环境中发生的倾销之战已导致此类服务成本的惊人降低。
我们将以Google(GKE)的Kubernetes引擎为例分析以下情况,但是,如果Google不适合您,您还可以查看Amazon(EKS)或Microsoft(AKS)的报价。 要构建自己的Kubernetes集群,我们需要:

  • 域名(每年约10美元,具体取决于域名)
  • Cloudflare DNS托管(免费)
  • GKE Kubernetes三节点集群(〜$ 5 /月)
  • Web应用程序作为Docker容器上传到Google容器注册表(GCR)(免费)
  • 用于Kubernetes配置的许多Yaml文件

为了节省更多,我们将尝试在没有Google输入控制器的情况下进行操作。 相反,我们将在每个节点上将Nginx用作守护程序,并创建自己的运算符,该运算符会将工作节点的外部IP地址与Cloudflare同步。

Google配置

首先,请转到console.cloud.google.com并创建一个项目(如果尚未创建)。 您还需要创建一个计费帐户。 然后,通过汉堡菜单,进入Kubernetes页面并创建一个新集群。 接下来是您需要做的:

  • 选择区域作为位置类型。
  • 我表示我的位置为us-central1-a
  • 选择您的kubernetes版本
  • 使用最便宜的实例类型(f1-micro)创建3个节点的池。
  • 对于此节点池,在“高级”屏幕上,将启动磁盘大小设置为10GB,启用挤压节点(它们更便宜),启用自动更新和自动处理。
  • 在节点池下,您会发现许多其他选项。 我们要禁用HTTP负载平衡(GCP中的负载平衡是昂贵的),并且还禁用与StackDriver相关的整个经济性(它也可能是昂贵的,并且根据我的经验,不是很可靠)。 同时关闭kubernetes指示灯面板。

放置所有这些选项后,您可以继续下一步:创建集群。 保存方法如下:

  • Kubernetes控制平面:免费,因为Google不向主机节点收费
  • Kubernetes工作节点:每月5.04美元,作为一个规则,三个微节点每月将花费您11.65美元,并且使它们排挤后,我们会将这个费率降低到7.67美元/月,并在Always Free下降低到5.04美元。
  • 储存费用:免费。 我们免费获得30GB的永久磁盘空间,因此在上面我们选择了10GB的大小。
  • 负载平衡的成本:免费,我们关闭了HTTP负载平衡,因为这将花费我们18美元/月。 而是在每个节点上运行我们自己的HTTP代理,并将DNS定向到公共IP。
  • 网络费用:免费,出口功能保持免费,直到您选择每月1GB。 (接下来,每下一千兆字节的成本为8美分)

因此,我们建立了一个由3个节点组成的Kubernetes集群,它的价格与唯一的Digital Ocean机器相同。

除了配置GKE,您还需要配置几个防火墙规则,以便您可以从外部访问我们主机的HTTP端口。 在汉堡菜单中找到VPC网络条目,然后转到防火墙规则,并添加IP地址范围为0.0.0.0/0的TCP端口80和443的规则。



防火墙规则

本地设置

因此,我们提出并启动了集群,现在让我们对其进行配置。 按照gcloud的说明安装gcloud工具。 安装后,您可以执行以下操作进行配置:

 gcloud auth login 

当然,您仍然必须安装docker,然后将其绑定到GCR,以便可以发送容器:

 gcloud auth configure-docker 

您还可以按照此处概述的说明安装和配置kubectl

简化:

 gcloud components install kubectl gcloud config set project PROJECT_ID gcloud config set compute/zone COMPUTE_ZONE gcloud container clusters get-credentials CLUSTER_NAME 

顺便说一句,所有这些工具包都可以在Windows,OSX或Linux上运行只是一个童话。 作为有时在Windows下完成此类操作的人,我承认这是一个令人惊喜的惊喜。

Web应用程序构建

Web应用程序可以用任何编程语言编写。 容器允许您抽象特定内容。 我们必须创建一个监听端口的HTTP应用程序。 我更喜欢Go来达到这种目的,但是为了进行更改,我们将尝试使用Crystal。 创建main.cr文件:

 # crystal-www-example/main.cr require "http/server" Signal::INT.trap do exit end server = HTTP::Server.new do |context| context.response.content_type = "text/plain" context.response.print "Hello world from crystal-www-example! The time is #{Time.now}" end server.bind_tcp("0.0.0.0", 8080) puts "Listening on http://0.0.0.0:8080" server.listen 

我们还需要一个Dockerfile:

 # crystal-www-example/Dockerfile FROM crystallang/crystal:0.26.1 as builder COPY main.cr main.cr RUN crystal build -o /bin/crystal-www-example main.cr --release ENTRYPOINT [ "/bin/crystal-www-example" ] 

要构建和测试我们的应用程序,请运行:

 docker build -t gcr.io/PROJECT_ID/crystal-www-example:latest . docker run -p 8080:8080 gcr.io/PROJECT_ID/crystal-www-example:latest 

然后转到位于本地主机的浏览器:8080。 建立了此机制后,我们可以通过运行以下命令将应用程序发送到GCR:

 docker push gcr.io/PROJECT_ID/crystal-www-example:latest 

配置Kubernetes

我的Kubernetes配置在这里

对于此示例,我们将必须创建几个yaml文件,其中将显示我们的各种服务,然后运行kubectl apply在群集中对其进行配置。 Kubernetes配置是描述性的,所有这些yaml文件都告诉Kubernetes我们想要获得什么状态。 从广义上讲,这就是我们要做的事情:

  • 为我们的Crystal-www-example Web应用程序创建部署和服务
  • 为Nginx创建守护程序集(服务集)和配置映射(配置映射)
  • 我们启动了自己的应用程序,以将IP节点与Cloudflare用于DNS同步

Web应用程序配置

首先,让我们配置Web应用程序:(确保将PROJECT_ID替换为您的项目ID)

 # kubernetes-config/crystal-www-example.yaml apiVersion: apps/v1 kind: Deployment metadata: name: crystal-www-example labels: app: crystal-www-example spec: replicas: 1 selector: matchLabels: app: crystal-www-example template: metadata: labels: app: crystal-www-example spec: containers: - name: crystal-www-example image: gcr.io/PROJECT_ID/crystal-www-example:latest ports: - containerPort: 8080 --- kind: Service apiVersion: v1 metadata: name: crystal-www-example spec: selector: app: crystal-www-example ports: - protocol: TCP port: 8080 targetPort: 8080 

这将创建一个Deployment(扩展的配置),根据该Kubernetes必须创建一个容器(我们的docker容器将在其中工作)以及一个我们将用于在集群中查找服务的服务。 要应用此配置,请运行(从kubernetes-config目录中):

 kubectl apply -f 

您可以像这样测试它:

 kubectl get pod #     : # crystal-www-example-698bbb44c5-l9hj9 1/1 Running 0 5m 


我们还可以创建用于访问的代理API:

 kubectl proxy 

然后转到: localhost :8001 / api / v1 /名称空间/默认/服务/ crystal-www-example /代理/

NGINX配置

通常,在使用HTTP服务时,Kubernetes使用输入控制器。 不幸的是,Google的HTTP负载平衡器太昂贵了,因此我们不会使用它,而是使用我们自己的HTTP代理并手动进行配置(这听起来很吓人,但实际上非常简单)。

为此,请使用“后台驻留程序设置和配置映射”。 守护程序集是在每个节点上运行的应用程序。 原则上,Config Map是一个小文件,我们可以将其安装在容器中。 该文件将存储Nginx配置。
yaml文件如下所示:

 apiVersion: apps/v1 kind: DaemonSet metadata: name: nginx labels: app: nginx spec: selector: matchLabels: app: nginx template: metadata: labels: app: nginx spec: hostNetwork: true dnsPolicy: ClusterFirstWithHostNet containers: - image: nginx:1.15.3-alpine name: nginx ports: - name: http containerPort: 80 hostPort: 80 volumeMounts: - name: "config" mountPath: "/etc/nginx" volumes: - name: config configMap: name: nginx-conf --- apiVersion: v1 kind: ConfigMap metadata: name: nginx-conf data: nginx.conf: | worker_processes 1; error_log /dev/stdout info; events { worker_connections 10; } http { access_log /dev/stdout; server { listen 80; location / { proxy_pass http://crystal-www-example.default.svc.cluster.local:8080; } } } 

这就是我们在nginx容器中挂载配置卡的nginx.conf文件的方式。 我们还为另外两个字段设置值: hostNetwork: true ,以便您可以绑定主机端口并从外部dnsPolicy: ClusterFirstWithHostNet nginx,并且可以绑定dnsPolicy: ClusterFirstWithHostNet以便可以访问集群中的服务。 如果不这样做,那么我们将获得完全标准的配置。

应用这些表达式,您可以通过节点的公共ip访问nginx。

您可以通过以下方法进行验证:

 kubectl get node -o yaml # look for: # - address: ... # type: ExternalIP 

因此,现在可以从Internet访问我们的Web应用程序。 仍然需要为该应用程序起一个漂亮的名字。

DNS连接

要求为集群节点设置3条DNS记录:



UI Cloudflare中的条目

然后添加一个CNAME记录以指向这些A记录。 (例如kubernetes.example.com的www.example.com CNAME)。 这可以手动完成,但更好的做法是自动完成,因此,如果我们需要扩展或替换DNS记录中的节点,此信息也会自动更新。

我认为这个示例也很好地说明了如何将部分工作委托给Kubernetes,而不是试图克服它。 Kubernetes理解脚本并具有强大的API,并且您可以使用自己的组件填充现有空间,而这些组件并不难编写。 为此,我在Go上制作了一个小型应用程序,该应用程序可从以下地址获得: kubernetes-cloudflare-sync

首先,创建一个线人:

 factory := informers.NewSharedInformerFactory(client, time.Minute) lister := factory.Core().V1().Nodes().Lister() informer := factory.Core().V1().Nodes().Informer() informer.AddEventHandler(cache.ResourceEventHandlerFuncs{ AddFunc: func(obj interface{}) { resync() }, UpdateFunc: func(oldObj, newObj interface{}) { resync() }, DeleteFunc: func(obj interface{}) { resync() }, }) informer.Run(stop) 

每当节点更改时,它将调用我的重新同步功能。 然后,我使用Cloudflare API库同步API,如下所示:

 var ips []string for _, node := range nodes { for _, addr := range node.Status.Addresses { if addr.Type == core_v1.NodeExternalIP { ips = append(ips, addr.Address) } } } sort.Strings(ips) for _, ip := range ips { api.CreateDNSRecord(zoneID, cloudflare.DNSRecord{ Type: "A", Name: options.DNSName, Content: ip, TTL: 120, Proxied: false, }) } 

然后,与我们的Web应用程序一样,我们在Kubernetes中将该应用程序作为部署启动:

 apiVersion: apps/v1 kind: Deployment metadata: name: kubernetes-cloudflare-sync labels: app: kubernetes-cloudflare-sync spec: replicas: 1 selector: matchLabels: app: kubernetes-cloudflare-sync template: metadata: labels: app: kubernetes-cloudflare-sync spec: serviceAccountName: kubernetes-cloudflare-sync containers: - name: kubernetes-cloudflare-sync image: gcr.io/PROJECT_ID/kubernetes-cloudflare-sync args: - --dns-name=kubernetes.example.com env: - name: CF_API_KEY valueFrom: secretKeyRef: name: cloudflare key: api-key - name: CF_API_EMAIL valueFrom: secretKeyRef: name: cloudflare key: email 

我们将需要通过指定cloudflare api密钥和邮件地址来创建Kubernetes机密:

 kubectl create secret generic cloudflare --from-literal=email='EMAIL' --from-literal=api-key='API_KEY' 

我们还需要创建一个服务帐户(授予对Kubernetes API的部署访问权限以检索节点)。 首次运行(尤其是对于GKE):

 kubectl create clusterrolebinding cluster-admin-binding --clusterrole cluster-admin --user YOUR_EMAIL_ADDRESS_HERE 


然后申请:

 apiVersion: v1 kind: ServiceAccount metadata: name: kubernetes-cloudflare-sync --- apiVersion: rbac.authorization.k8s.io/v1 kind: ClusterRole metadata: name: kubernetes-cloudflare-sync rules: - apiGroups: [""] resources: ["nodes"] verbs: ["list", "watch"] --- apiVersion: rbac.authorization.k8s.io/v1 kind: ClusterRoleBinding metadata: name: kubernetes-cloudflare-sync-viewer roleRef: apiGroup: rbac.authorization.k8s.io kind: ClusterRole name: kubernetes-cloudflare-sync subjects: - kind: ServiceAccount name: kubernetes-cloudflare-sync namespace: default 

与RBAC合作有点乏味,但我希望这里一切都清楚。 当配置准备就绪,并且我们的应用程序可以与Cloudflare一起使用时,可以在任何节点上进行任何更改来更新该应用程序。

结论

Kubernetes必将成为管理大型系统的旗舰技术。 , Kubernetes , Kubernetes , Kubernetes , Kubernetes .

, Kubernetes : , . – !

Source: https://habr.com/ru/post/zh-CN433192/


All Articles