速来报名!AICon北京站鸿蒙专场~ 了解详情
写点什么

Step by Step!Kubernetes 持续部署指南

  • 2020-05-18
  • 本文字数:6936 字

    阅读完需:约 23 分钟

Step by Step!Kubernetes持续部署指南

在很久很久以前的一份工作中,我的任务是将老式的 LAMP 堆栈切换到 Kubernetes 上。那会儿我的老板总是追逐新技术,认为只需要几天时间就能够完成新旧技术的迭代——鉴于那时我们甚至对容器的工作机制一无所知,所以不得不说老板的想法真的很大胆。


在阅读了官方文档并且搜索了很多信息之后,我们开始感到不知所措——有许多新的概念需要学习:pod、容器以及 replica 等。对我而言,Kubernetes 似乎只是为一群聪明的开发者而设计的。


然后我做了我在这一状况下常做的事:通过实践来学习。通过一个简单的例子可以很好地理解错综复杂的问题,所以我自己一步一步完成了整个部署过程。


最后,我们做到了,虽然远未达到规定的一周时间——我们花了将近一个月的时间来创建三个集群,包括它们的开发、测试和生产。


本文我将详细介绍如何将应用程序部署到 Kubernetes。阅读完本文之后,你将拥有一个高效的 Kubernetes 部署和持续交付工作流程。

持续集成与交付

持续集成是在每次应用程序更新时构建和测试的实践。通过以少量的工作,更早地检测到错误并立即解决。


集成完成并且所有测试都通过之后,我们就能够添加持续交付到自动化发布和部署的流程中。使用 CI/CD 的项目可以更频繁、更可靠地发布。


我们将使用 Semaphore,这是一个快速、强大且易用地持续集成和交付(CI/CD)平台,它能够自动执行所有流程:


1、 安装项目依赖项


2、 运行单元测试


3、 构建一个 Docker 镜像


4、 Push 镜像到 Docker Hub


5、 一键 Kubernetes 部署


对于应用程序,我们有一个 Ruby Sinatra 微服务,它暴露一些 HTTP 端点。该项目已包含部署所需的所有内容,但仍需要一些组件。

准备工作

在开始操作之前,你需要登录 Github 和 Semaphore 账号。此外,为后续方便拉取或 push Docker 镜像,你需要登录 Docker Hub。


接下来,你需要在计算机上安装一些工具:


  • Git:处理代码

  • curl:网络的“瑞士军刀”

  • kubectl:远程控制你的集群


当然,千万不要忘了 Kubernetes。大部分的云供应商都以各种形式提供此服务,选择适合你的需求的即可。最低端的机器配置和集群大小足以运行我们示例的 app。我喜欢从 3 个节点的集群开始,但你可以只用 1 个节点的集群。


集群准备好之后,从你的供应商中下载 kubeconfig 文件。有些允许你直接从其 web 控制台下载,有些则需要帮助程序。我们需要此文件才能连接到集群。


有了这个,我们已经可以开始了。首先要做的是 fork 存储库。

Fork 存储库

在这篇文章中 fork 我们将使用的演示应用程序。


  1. 访问 semaphore-demo-ruby-kubernetes 存储库,并且点击右上方的 Fork 按钮

  2. 点击 Clone or download 按钮并且复制地址

  3. 复制存储库:


$ git clone https://github.com/your_repository_path…
复制代码


使用 Semaphore 连接新的存储库


1、 登录到你的 Semaphore


2、 点击侧边栏的链接,创建一个新项目


3、 点击你的存储库旁【 Add Repository 】按钮

使用 Semaphore 测试

持续集成让测试变得有趣并且高效。一个完善的 CI 流水线能够创建一个快速反馈回路以在造成任何损失之前发现错误。我们的项目附带一些现成的测试。


打开位于.semaphore/semaphore.yml 的初始流水线文件,并快速查看。这个流水线描述了 Semaphore 构建和测试应用程序所应遵循的所有步骤。它从版本和名称开始。


version: v1.0name: CI
复制代码


接下来是 agent,它是为 job 提供动力的虚拟机。我们可以从 3 种类型中选择:


agent:  machine:    type: e1-standard-2    os_image: ubuntu1804
复制代码


Block(块)、任务以及 job 定义了在流水线的每个步骤中要执行的操作。在 Semaphore,block 按照顺序运行,与此同时,在 block 中的 job 也会并行运行。流水线包含 2 个 block,一个是用于库安装,一个用于运行测试。



第一个 block 下载并安装了 Ruby gems。


- name: Install dependencies  task:    jobs:      - name: bundle install        commands:          - checkout          - cache restore gems-$SEMAPHORE_GIT_BRANCH-$(checksum Gemfile.lock),gems-$SEMAPHORE_GIT_BRANCH,gems-master          - bundle install --deployment --path .bundle          - cache store gems-$SEMAPHORE_GIT_BRANCH-$(checksum Gemfile.lock) .bundle
复制代码


Checkout 复制了 Github 里的代码。既然每个 job 都在完全隔离的机器里运行,那么我们必须依赖缓存(cache)来在 job 运行之间存储和检索文件。


blocks:  - name: Install dependencies    task:      jobs:        - name: bundle install          commands:            - checkout            - cache restore gems-$SEMAPHORE_GIT_BRANCH-$(checksum Gemfile.lock),gems-$SEMAPHORE_GIT_BRANCH,gems-master            - bundle install --deployment --path .bundle            - cache store gems-$SEMAPHORE_GIT_BRANCH-$(checksum Gemfile.lock) .bundle
复制代码


第二个 block 进行测试。请注意我们重复使用了 checkout 和 cache 的代码以将初始文件放入 job 中。最后一个命令用于启动 RSpec 测试套件。


- name: Tests  task:    jobs:      - name: rspec        commands:          - checkout          - cache restore gems-$SEMAPHORE_GIT_BRANCH-$(checksum Gemfile.lock),gems-$SEMAPHORE_GIT_BRANCH,gems-master          - bundle install --deployment --path .bundle          - bundle exec rspec
复制代码


最后一个部分我们来看看 Promotion。Promotion 能够在一定条件下连接流水线以创建复杂的工作流程。所有 job 完成之后,我们使用 auto_promote_on 来启动下一个流水线。


promotions:  - name: Dockerize    pipeline_file: docker-build.yml    auto_promote_on:      - result: passed
复制代码


工作流程继续执行下一个流水线。

构建 Docker 镜像

我们可以在 Kubernetes 上运行任何东西,只要它打包在 Docker 镜像中。在这一部分,我们将学习如何构建镜像。


我们的 Docker 镜像将包含应用程序的代码、Ruby 以及所有的库。让我们先来看一下 Dockerfile:


FROM ruby:2.5 RUN apt-get update -qq && apt-get install -y build-essential ENV APP_HOME /appRUN mkdir $APP_HOMEWORKDIR $APP_HOME ADD Gemfile* $APP_HOME/RUN bundle install --without development test ADD . $APP_HOME EXPOSE 4567 CMD ["bundle", "exec", "rackup", "--host", "0.0.0.0", "-p", "4567"]
复制代码


Dockerfile 就像一个详细的菜谱,包含所有构建容器镜像所需要的步骤和命令:


1、 从预构建的 ruby 镜像开始


2、 使用 apt-get 安装构建工具


3、 复制 Gemfile,因为它具有所有的依赖项


4、 用 bundle 安装它们


5、 复制 app 的源代码


6、 定义监听端口和启动命令


我们将在 Semaphore 环境中 bake 我们的生产镜像。然而,如果你想要在计算机上进行一个快速的测试,那么请输入:


$ docker build . -t test-image
复制代码


使用 Docker 运行和暴露内部端口 4567 以在本地启动服务器:


$ docker run -p 4567:4567 test-image
复制代码


你现在可以测试一个可用的 HTTP 端点:


$ curl -w "\n" localhost:4567hello world :))
复制代码

添加 Docker Hub 账户到 Semaphore

Semaphore 有一个安全的机制以存储敏感信息,如密码、令牌或密钥等。为了能够 push 镜像到你的 Docker Hub 镜像仓库中,你需要使用你的用户名和密码来创建一个 Secret:


  1. 打开你的 Semaphore

  2. 在左侧导航栏中,点击【 Secret

  3. 点击【 Creat New Secret

  4. Secret 的名字应该是 Dockerhub,键入登录信息(如下图所示),并保存。


构建 Docker 流水线

这个流水线开始构建并且 push 镜像到 Docker Hub,它仅仅有 1 个 block 和 1 个 job:



这次,我们需要使用更好的性能,因为 Docker 往往更加耗费资源。我们选择具有四个 CPU,8GB RAM 和 35GB 磁盘空间的中端机器 e1-standard-4:


version: v1.0name: Docker buildagent:  machine:    type: e1-standard-4    os_image: ubuntu1804
复制代码


构建 block 通过登录到 Docker Hub 启动,用户名和密码可以从我们刚创建的 secret 导入。登录之后,Docker 可以直接访问镜像仓库。


下一个命令是 docker pull,它试图拉取最新镜像。如果找到镜像,那么 Docker 可能能够重新使用其中的一些层,以加速构建过程。如果没有最新镜像,也无需担心,只是需要花费长一点的时间来构建。


最后,我们 push 新的镜像。注意,这里我们使用 SEMAPHORE_WORKFLOW_ID 变量来标记镜像。


blocks:  - name: Build    task:      secrets:        - name: dockerhub      jobs:      - name: Docker build        commands:          - echo "${DOCKER_PASSWORD}" | docker login -u "${DOCKER_USERNAME}" --password-stdin          - checkout          - docker pull "${DOCKER_USERNAME}"/semaphore-demo-ruby-kubernetes:latest || true          - docker build --cache-from "${DOCKER_USERNAME}"/semaphore-demo-ruby-kubernetes:latest -t "${DOCKER_USERNAME}"/semaphore-demo-ruby-kubernetes:$SEMAPHORE_WORKFLOW_ID .          - docker images          - docker push "${DOCKER_USERNAME}"/semaphore-demo-ruby-kubernetes:$SEMAPHORE_WORKFLOW_ID
复制代码


当镜像准备完毕,我们进入项目的交付阶段。我们将用手动 promotion 来扩展我们的 Semaphore 流水线。


promotions:  - name: Deploy to Kubernetes    pipeline_file: deploy-k8s.yml
复制代码


要进行第一次自动构建,请进行 push:


$ touch test-build$ git add test-build$ git commit -m "initial run on Semaphore“$ git push origin master
复制代码


镜像准备完成之后,我们就可以进入部署阶段。

部署到 Kubernetes

自动部署是 Kubernetes 的强项。我们所需要做的就是告诉集群我们最终的期望状态,剩下的将由它来负责。


然而,在部署之前,你必须将 kubeconfig 文件上传到 Semaphore。

上传 Kubeconfig 到 Semaphore

我们需要第二个 secret:集群的 kubeconfig。这个文件授予可以对它的管理访问权限。因此,我们不希望将文件签入存储库。


创建一个名为 do-k8s 的 secret 并且将 kubeconfig 文件上传到/home/semaphore/.kube/dok8s.yaml 中:


部署清单

尽管 Kubernetes 已经是容器编排平台,但是我们不直接管理容器。实际上,部署的最小单元是 pod。一个 pod 就好像一群形影不离的朋友,总是一起去同一个地方。因此要保证在 pod 中的容器运行在同一个节点上并且有相同的 IP。它们可以同步启动和停止,并且由于它们在同一台机器上运行,因此它们可以共享资源。


pod 的问题在于它们可以随时启动和停止,我们没办法确定它们会被分配到的 pod IP。要把用户的 http 流量转发,还需要提供一个公共 IP 和一个负载均衡器,它负责跟踪 pod 和转发客户端的流量。


打开位于 deploymente.yml 的文件。这是一个部署我们应用程序的清单,它被 3 个 dash 分离成两个资源。第一个,部署资源:


apiVersion: apps/v1kind: Deploymentmetadata:  name: semaphore-demo-ruby-kubernetesspec:  replicas: 1  selector:    matchLabels:      app: semaphore-demo-ruby-kubernetes  template:    metadata:      labels:        app: semaphore-demo-ruby-kubernetes    spec:      containers:        - name: semaphore-demo-ruby-kubernetes          image: $DOCKER_USERNAME/semaphore-demo-ruby-kubernetes:$SEMAPHORE_WORKFLOW_ID
复制代码


这里有几个概念需要厘清:


  • 资源都有一个名称和几个标签,以便组织

  • Spec 定义了最终期望的状态,template 是用于创建 Pod 的模型。

  • Replica 设置要创建的 pod 的副本数。我们经常将其设置为集群中的节点数。既然我们使用了 3 个节点,我将这一命令行更改为 replicas:3


第二个资源是服务。它绑定到端口 80 并且将 HTTP 流量转发到部署中的 pod:


--- apiVersion: v1kind: Servicemetadata:  name: semaphore-demo-ruby-kubernetes-lbspec:  selector:    app: semaphore-demo-ruby-kubernetes  type: LoadBalancer  ports:    - port: 80      targetPort: 4567
复制代码


Kubernetes 将 selector 与标签相匹配以便将服务与 pod 连接起来。因此,我们在同一个集群中有许多服务和部署并且根据需要连接他们。

部署流水线

我们现在进入 CI/CD 配置的最后一个阶段。这时,我们有一个定义在 semaphore.yml 的 CI 流水线,以及定义在 docker-build.yml 的 Docker 流水线。在这一步中,我们将部署到 Kubernetes。


打开位于.semaphore/deploy-k8s.yml 的部署流水线:


version: v1.0name: Deploy to Kubernetesagent:  machine:    type: e1-standard-2    os_image: ubuntu1804
复制代码


两个 job 组成最后的流水线:



Job 1 开始部署。导入 kubeconfig 文件之后,envsubst 将 deployment.yaml 中的占位符变量替换为其实际值。然后,kubectl apply 将清单发送到集群。


blocks:  - name: Deploy to Kubernetes    task:      secrets:        - name: do-k8s        - name: dockerhub       env_vars:        - name: KUBECONFIG          value: /home/semaphore/.kube/dok8s.yaml       jobs:      - name: Deploy        commands:          - checkout          - kubectl get nodes          - kubectl get pods          - envsubst < deployment.yml | tee deployment.yml          - kubectl apply -f deployment.yml
复制代码


Job 2 将镜像标记为最新,以让我们能够在下一次运行中将其作为缓存使用。


- name: Tag latest release  task:    secrets:      - name: dockerhub    jobs:    - name: docker tag latest      commands:        - echo "${DOCKER_PASSWORD}" | docker login -u "${DOCKER_USERNAME}" --password-stdin        - docker pull "${DOCKER_USERNAME}"/semaphore-demo-ruby-kubernetes:$SEMAPHORE_WORKFLOW_ID        - docker tag "${DOCKER_USERNAME}"/semaphore-demo-ruby-kubernetes:$SEMAPHORE_WORKFLOW_ID "${DOCKER_USERNAME}"/semaphore-demo-ruby-kubernetes:latest        - docker push "${DOCKER_USERNAME}"/semaphore-demo-ruby-kubernetes:latest
复制代码


这是工作流程的最后一步了。

部署应用程序

让我们教我们的 Sinatra 应用程序唱歌。在 app.rb 中的 App 类中添加以下代码:


get "/sing" do  "And now, the end is near   And so I face the final curtain..."end
复制代码


推送修改的文件到 Github:


$ git add .semaphore/*$ git add deployment.yml$ git add app.rb$ git commit -m "test deployment”$ git push origin master
复制代码


等到 docker 构建流水线完成,你可以查看 Semaphore 的进度:



是时候进行部署了,点击 Promote 按钮,看它是否工作:



我们已经有了一个好的开始,现在就看 Kubernetes 的了。我们可以使用 kubectl 检查部署状态,初始状态是三个所需的 pod 并且零可用:


$ kubectl get deploymentsNAME                             DESIRED   CURRENT   UP-TO-DATE   AVAILABLE   AGEsemaphore-demo-ruby-kubernetes   3         0         0            0           15m
复制代码


几秒之后,pod 已经启动,reconciliation 已经完成:


$ kubectl get deploymentsNAME                             DESIRED   CURRENT   UP-TO-DATE   AVAILABLE   AGEsemaphore-demo-ruby-kubernetes   3         3         3            3           15m
复制代码


使用 get all 获得集群的通用状态,它显示了 pod、服务、部署以及 replica:


$ kubectl get allNAME                                                  READY   STATUS    RESTARTS   AGEpod/semaphore-demo-ruby-kubernetes-7d985f8b7c-454dh   1/1     Running   0          2mpod/semaphore-demo-ruby-kubernetes-7d985f8b7c-4pdqp   1/1     Running   0          119spod/semaphore-demo-ruby-kubernetes-7d985f8b7c-9wsgk   1/1     Running   0          2m34s  NAME                                        TYPE           CLUSTER-IP    EXTERNAL-IP    PORT(S)        AGEservice/kubernetes                          ClusterIP      10.12.0.1              443/TCP        24mservice/semaphore-demo-ruby-kubernetes-lb   LoadBalancer   10.12.15.50   35.232.70.45   80:31354/TCP   17m  NAME                                             DESIRED   CURRENT   UP-TO-DATE   AVAILABLE   AGEdeployment.apps/semaphore-demo-ruby-kubernetes   3         3         3            3           17m NAME                                                        DESIRED   CURRENT   READY   AGEreplicaset.apps/semaphore-demo-ruby-kubernetes-7d985f8b7c   3         3         3       2m3
复制代码


Service IP 在 pod 之后展示。对于我来说,负载均衡器被分配到外部 IP 35.232.70.45。需要将其更改为你的提供商分配给你的那个,然后我们来试试新的服务器。


$ curl -w "\n" http://YOUR_EXTERNAL_IP/sing
复制代码


现在,离结束已经不远了。

胜利近在咫尺

当你使用了正确的 CI/CD 解决方案之后,部署到 Kubernetes 并不是那么困难。你现在拥有一个 Kubernetes 的完全自动的持续交付流水线啦。


这里有几个建议可以让你在 Kubernetes 上随意 fork 并玩转 semaphore-demo-ruby-kubernetes:


  • 创建一个 staging 集群

  • 构建一个部署容器并且在里面运行测试

  • 使用更多微服务扩展项目


2020-05-18 17:59707

评论

发布
暂无评论
发现更多内容

997页字节跳动Java面试真题解析火爆全网,腾讯T3大佬亲自教你

Java 程序员 后端

BTAJ大厂最新面试题汇集,中级Java开发人员要掌握的技术

Java 程序员 后端

Github爆火的《高并发秒杀顶级教程》,尚学堂java资料,Java基础面试题

Java 程序员 后端

Java中级笔试题百度文库,java架构师直通车百度云,使用指南

Java 程序员 后端

7天拿到阿里Java岗位offer,2021腾讯Java面试题精选

Java 程序员 后端

分布式存储和区块链结合能碰撞出怎样的火花?

CECBC

BIO和NIO有啥区别,Redis灵魂14问

Java 程序员 后端

ELK性能优化实战总结,黑马java笔记与作业,Java面试基础知识点

Java 程序员 后端

flutter中文网,达内java教程视频,HTTP规范中的那些容易掉进去的坑

Java 程序员 后端

Java-SSM框架相关面试题整理,2021Java面试题知识点总结

Java 程序员 后端

60分钟快速掌握RabbitMQ,Java常用数据结构面试题

Java 程序员 后端

74道高级Java面试合集:nginx入门到精百度云,Java校招笔试面试题目

Java 程序员 后端

Alibaba高并发业务实战文档,java自学百度网盘,Java架构师知识体系

Java 程序员 后端

HTTPS面试常问全解析,黑马学习java,Java中高级工程师面试题及答案

Java 程序员 后端

让区块链技术在经济社会发展中发挥更大作用

CECBC

985研究生入职电网6个月,牛客网面经下载,血与泪的总结

Java 程序员 后端

docker面试题汇总,尚学堂尚硅谷java,已拿offer入职

Java 程序员 后端

Dubbo高频面试题+解析,宅家36天咸鱼翻身入职腾讯

Java 程序员 后端

在线手机号码VCF批量导入工具

入门小站

工具

GitHub标星8k!黑马springboot笔记,阿里Java校招面试题

Java 程序员 后端

60分钟快速掌握RabbitMQ,Java基础全套视频教程

Java 程序员 后端

BIO和NIO有啥区别,绝对干货分享

Java 程序员 后端

hash、set、zset的底层数据结构原理,字节Java面试必问

Java 程序员 后端

Javaweb框架面试题,尚学堂java全套资料百度云,附高频面试题合集

Java 程序员 后端

Javaweb面试问题,java教程马士兵全集,设计思想解读开源框架

Java 程序员 后端

阿里云容器服务多项重磅发布:高效智能、安全无界的新一代平台

阿里巴巴云原生

阿里云 容器 云原生 云栖大会

Github爆火的《高并发秒杀顶级教程》,2021最新Java框架体系架构面试题

Java 程序员 后端

95%Java开发者已收藏的十大开源库,手把手教你写Java项目文档

Java 程序员 后端

Java400道面试题通关宝典助你进大厂,Java后端工程师需要掌握的知识

Java 程序员 后端

80后程序员月薪30K+感慨中年危机,Java开发面试准备

Java 程序员 后端

996页阿里Java面试真题解析火爆全网,Java工程师笔试题目

Java 程序员 后端

Step by Step!Kubernetes持续部署指南_文化 & 方法_Rancher_InfoQ精选文章