之前,我们基本都是单体Web应用程序:大型的代码库,随着新的功能和特性不断发展,最后它们都会变成巨大的,缓慢移动的,难以管理的巨人。 现在,越来越多的开发人员,架构师和DevOps专家认为,使用微服务比使用大型单体应用更好。 通常,使用基于微服务的体系结构意味着将你的单体应用分成至少两个应用程序:前端应用程序和后端应用程序(API)。在决定使用微服务之后,出现了一个问题:在什么环境下运行微服务更好? 我应该选择什么来使我的服务稳定,易于管理和部署?简短的回答是:使用Docker!
在本文中,我将介绍容器,解释Kubernetes,并教你如何使用CircleCI将应用程序容器化和部署到Kubernetes集群。
Docker?什么是Docker?
Docker是一款旨在让DevOps(和你的生活)更轻松的工具。使用Docker,开发人员可以在容器中创建,部署和运行应用程序。容器允许开发人员使用所需的所有部件(例如库和其他依赖项)打包应用程序,并将其作为一个包发布出去。![1.png 1.png](http://dockone.io/uploads/article/20181104/7fcb29f561fe4f9eddbd2f46508b05ca.png?x-oss-process=image/resize,w_1400/format,webp)
使用容器,开发人员可以轻松将镜像(重新)部署到任何操作系统。 只需安装Docker,执行命令,你的应用程序即可启动并运行。哦,不要担心主机操作系统中新版本库的任何不一致。此外,您可以在同一主机上启动很多容器——不管是相同的应用程序还是其他应用程序,都没关系。
看起来Docker是一个很棒的工具。但是我应该如何以及在何处启动容器?
运行容器的方式有很多选择:
- AWS Elastic Container Service(AWS Fargate或具有水平和垂直自动伸缩的预留实例);
- Azure或Google Cloud中具有预定义Docker镜像的云实例(包含模板,实例组和自动缩放);
- 在你自己的服务器上;
- 当然还有Kubernetes!Kubernetes是2014年由Google工程师专门为虚拟化和容器创建的。
Kubernetes?那是什么?
Kubernetes是一个开源系统,允许你运行容器,管理容器,自动化部署,扩展部署,创建和配置Ingress,部署无状态或有状态应用程序以及许多其他内容。基本上,你可以启动一个或多个实例来安装Kubernetes,将其作为Kubernetes集群进行操作。然后获取Kubernetes集群的API端点,配置kubectl(管理Kubernetes集群的工具),Kubernetes即可投入使用。那我为什么要用Kubernetes呢?
使用Kubernetes,你可以最大限度地利用计算资源。 通过Kubernetes,你将成为你的船(基础设施)的船长,Kubernetes将为你扬帆。 使用Kubernetes,你的服务将是高可用的。最重要的是,通过Kubernetes,你将节省大量资金。看起来很有前途,特别是如果它会省钱!让我们来谈谈它!
Kubernetes日复一日地更加受欢迎。让我们更深入地研究一下这幕后的内容。
![2.png 2.png](http://dockone.io/uploads/article/20181104/b1d34cf65a96e6a56c055abb8ba85695.png?x-oss-process=image/resize,w_1400/format,webp)
译者注:上图有个小错误,kubectl写成了kubecti。
Kubernetes是整个系统的名称,但与你的汽车一样,有许多小部件可以完美地彼此协同工作以使Kubernetes发挥其各种作用。让我们来了解它们分别是什么。
主节点(Master Node)——整个Kubernetes集群的控制面板。主节点的组件可以在群集中的任何节点上运行。关键组成部分是:
- API Server:所有REST命令的入口点,是用户可以访问的主节点的唯一组件。
- Datastore:Kubernetes群集使用的强大,一致且高可用的键值存储。
- Scheduler:监视新创建的Pod并将它们分配给节点。Pod和Services部署到节点上主要由Scheduler来控制。
- Controller manager:管理着处理集群中日常任务的所有控制器。
- Worker Node:主要的节点代理,也称为minion(旧版本Kubernetes的叫法)。Pod在这里运行。工作节点包含所有必要的服务,这些服务包括管理容器之间的网络,与主节点通信以及将资源分配给已调度容器等。
- Docker:运行在每个工作节点上,用来下载镜像和启动容器。
- Kubelet:监视Pod的状态并确保容器已启动并运行。它还与数据存储通信,获取有关服务的信息并记录新创建的服务的详细信息。
- Kube-proxy:单个工作节点上的服务的网络代理和负载均衡。它负责流量路由。
- Kubectl:一个CLI工具,供用户与Kubernetes API Server进行通信。
那什么是Pod和Services?
Pod是Kubernetes集群中最小的单元,就像一座巨大建筑物墙上的一块砖。 Pod是一组需要一起运行并且可以共享资源的容器(Linux名称空间,cgroups,IP地址)。Pod的生命周期是非永久性的。Service是在多个Pod之上的抽象,通常需要在它上面有层代理,以便其他服务通过虚拟IP地址与其通信。
一个简单部署例子
![3.png 3.png](http://dockone.io/uploads/article/20181104/3d43e2b39362d95425cea2ddfb1fb424.png?x-oss-process=image/resize,w_1400/format,webp)
我将使用简单的Ruby on Rails应用程序和GKE作为运行Kubernetes的平台。实际上,你可以在AWS或Azure中使用Kubernetes,甚至可以在你自己的硬件中创建集群,或使用你minikube在本地运行Kubernetes,所有的选项你都可以在这个页面
Setup - Kubernetes
上找到。
这个app的源码你可以在 GitHub - d-kononov/simple-rails-app-in-k8s 里找到。
要创建新的Rails应用程序,请执行:
rails new blog
在
config/database.yml
文件中配置生产MySQL连接:
production: adapter: mysql2 encoding: utf8 pool: 5 port: 3306 database: <%= ENV['DATABASE_NAME'] %> host: 127.0.0.1 username: <%= ENV['DATABASE_USERNAME'] %> password: <%= ENV['DATABASE_PASSWORD'] %>
创建Article model、controller、views和migration,请执行:
rails g scaffold Article title:string description:text
添加Gems到Gemfile:
gem 'mysql2', '< 0.6.0', '>= 0.4.4' gem 'health_check'
创建Docker镜像,请下载 Dockerfile ,并执行:
docker build -t REPO_NAME/IMAGE_NAME:TAG . && docker push REPO_NAME/IMAGE_NAME:TAG
是时候创建一个Kubernetes集群了。打开GKE页面并创建Kubernetes集群。创建集群后,单击“连接”按钮并复制命令——确保你已安装和配置了
gCloud CLI
工具(
如何
)和kubectl。在PC上执行复制的命令并检查与Kubernetes集群的连接;执行
kubectl cluster-info
。
该应用程序已准备好部署到Kubernetes群集。让我们创建一个MySQL数据库。在gCloud控制台中打开SQL页面,为应用程序创建一个MySQL数据库实例。实例准备就绪后,创建用户和数据库并复制实例连接名称。
此外,我们需要在
API和服务
页面中创建一个
service account
密钥,以便从sidecar容器访问MySQL数据库。您可以在
此处
找到有关该流程的更多信息。 将下载的文件重命名为
service-account.json
。 我们稍后会用到这个文件。
我们准备将我们的应用程序部署到Kubernetes,但首先,我们应该为我们的应用程序创建
secret
——在Kubernetes中创建用于存储敏感数据的secret对象。上传之前下载的
service-account.json
文件:
kubectl create secret generic mysql-instance-credentials \ --from-file=credentials.json=service-account.json
为应用程序创建secrets:
kubectl create secret generic simple-app-secrets \ --from-literal=username=$MYSQL_PASSWORD \ --from-literal=password=$MYSQL_PASSWORD \ --from-literal=database-name=$MYSQL_DB_NAME \ --from-literal=secretkey=$SECRET_RAILS_KEY
请不要忘记替换必要的配置,或者记得正确地设置环境变量。
在创建deployment之前,让我们看一下 deployment.yaml 。我把三个文件连成一个;第一部分是一个Service,它将公开端口80并转发到端口80和到3000的所有连接。该Service有一个selector,Service通过它知道哪个Pod应该转发连接。
该文件的下一部分是Deployment,它描述了将在Pod中启动的部署策略容器,环境变量,资源,探针,每个容器的mounts以及其他信息。
最后一部分是Horizontal Pod Autoscaler。HPA有一个非常简单的配置。请记住,如果您未在部署部分中为容器设置资源,则HPA将无法运行。
您可以在GKE编辑页面中为Kubernetes集群配置Vertical Autoscaler。它也有一个非常简单的配置。
是时候将它发布到GKE集群了!首先,我们通过 rake-tasks-job.yaml 进行部署。 执行:
kubectl apply -f rake-tasks-job.yaml
这个Job对于CI/CD很有用。
kubectl apply -f deployment.yaml
上面这条命令用来创建Service、Deployment和HPA。
然后通过
kubectl get pods -w
命令来检查你的Pod:
NAME READY STATUS RESTARTS AGE sample-799bf9fd9c-86cqf 2/2 Running 0 1m sample-799bf9fd9c-887vv 2/2 Running 0 1m sample-799bf9fd9c-pkscp 2/2 Running 0 1m
现在让我们为应用创建一个Ingress:
- 创建一个静态IP:
gcloud compute addresses create sample-ip --global
- 创建Ingress:
kubectl apply -f ingress.yaml
- 检查Ingress是否创建成功和查看它的IP地址:
kubectl get ingress -w
- 为你的应用创建域名或者子域名
CI/CD
让我们使用CircleCI创建一个CI/CD管道。实际上,使用CircleCI创建CI/CD管道很容易,但请记住,快而脏的未经过测试的全自动部署过程仅适用于小型项目,但请不要在严肃的项目上这样做。如果任何新代码在生产中出现问题,那么你将会损失巨大。这就是为什么你应该考虑设计一个强大的部署过程,在完全推出之前启动canary任务,在canary启动后检查日志中的错误,等等。目前,我们有一个简单的小项目,所以让我们创建一个完全自动化,无测试的CI/CD部署过程。首先,您应该将CircleCI与您的代码仓库进行集成——你可以在 此处 找到具体内容。 然后我们应该创建一个包含CircleCI系统指令的配置文件。Config看起来很简单。要点是GitHub仓库中有两个分支:master和production。
- 主分支用于开发,用于新代码。当有人将新代码推送到主分支时,CircleCI启动主分支构建和测试代码的工作流。
- 生产分支用于将新版本部署到生产环境。生产分支的工作流程如下:推送新代码(如果从主分支到生产开放PR则更好)以触发新的构建和部署过程;在构建过程中,CircleCI创建新的Docker镜像,将其推送到GCR并创建新的部署;如果失败,CircleCI将触发回滚过程。
在运行任何构建之前,您应该在CircleCI中配置项目。在API和GCloud中的Service页面中创建一个新的service account,具有以下角色:完全访问GCR和GKE,打开下载的JSON文件并复制内容,然后在CircleCI的项目设置中创建一个新的环境变量GCLOUD_SERVICE_KEY并将service account文件的内容粘贴为值。 此外,您需要创建下一个env vars:GOOGLE_PROJECT_ID(可以在GCloud控制台主页上找到它),GOOGLE_COMPUTE_ZONE(GKE集群的区域)和GOOGLE_CLUSTER_NAME(GKE集群名称)。
CircleCI的最后一步(部署)如下所示:
kubectl patch deployment sample -p '{"spec":{"template":{"spec":{"containers":[{"name":"sample","image":"gcr.io/test-d6bf8/simple:'"$CIRCLE_SHA1"'"} ] } } } }' if ! kubectl rollout status deploy/sample; then echo "DEPLOY FAILED, ROLLING BACK TO PREVIOUS" kubectl rollout undo deploy/sample # Deploy failed -> notify slack else echo "Deploy succeeded, current version: ${CIRCLE_SHA1}" # Deploy succeeded -> notify slack fi deployment.extensions/sample patched Waiting for deployment "sample" rollout to finish: 2 out of 3 new replicas have been updated... Waiting for deployment "sample" rollout to finish: 2 out of 3 new replicas have been updated... Waiting for deployment "sample" rollout to finish: 2 out of 3 new replicas have been updated... Waiting for deployment "sample" rollout to finish: 1 old replicas are pending termination... Waiting for deployment "sample" rollout to finish: 1 old replicas are pending termination... Waiting for deployment "sample" rollout to finish: 1 old replicas are pending termination... Waiting for deployment "sample" rollout to finish: 2 of 3 updated replicas are available... Waiting for deployment "sample" rollout to finish: 2 of 3 updated replicas are available... deployment "sample" successfully rolled out Deploy succeeded, current version: 512eabb11c463c5431a1af4ed0b9ebd23597edd9
总结
看起来创建新的Kubernetes集群的过程并不那么难!CI/CD自动部署过程也非常棒!是!Kubernetes太棒了!使用Kubernetes,你的系统将更加稳定,易于管理,并使你成为系统的“船长”。更不用说,Kubernetes对系统施加了一些魔法,并为您的营销提供了+100分!
现在你已经掌握了基础知识,可以进一步将其转换为更高级的配置。我计划在以后的文章中介绍更多内容,但与此同时,有一个挑战:使用位于集群内的有状态数据库(包括用于备份的sidecar Pod)为应用程序创建一个强大的Kubernetes集群,在其中安装Jenkins用于CI/CD管道,让Jenkins使用Pod作为构建的slave。使用certmanager为Ingress添加/获取SSL证书。使用Stackdriver为应用程序创建监控和报警系统。
Kubernetes非常棒,因为它很容易扩展,没有供应商锁定,并且,因为你为实例付费,所以可以省钱。然而,不是每个人都是Kubernetes专家或者有时间建立一个新的集群。这里有一个可选方案:关于如何构建有效的初始部署管道并执行更少的操作任务,我的同事Toptaler Amin Shah Gilani使用Heroku,GitLab CI以及他能想到的其他自动化部署工具做了一套教程CI/CD:如何部署有效的初始化部署管道。
本文转自DockOne-Kubernetes部署实操教程