写点什么

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:59797

评论

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

OverOps在根本原因分析中重要性

阿泽🧸

10月月更 OverOps

“程”风破浪的开发者|OpenHarmony 开发环境搭建

鸿蒙之旅

OpenHarmony 10月月更 “程”风破浪的开发者

构建超级自动化平台成为战略技术趋势——Gartner:可观测性应用将成为数据驱动型决策的最强大来源

九科Ninetech

RPA 流程挖掘 数智化转型

css学习笔记5

虾仁疙瘩汤

CSS css3 10月月更

架构---作业3

李某人

架构训练营 #架构训练营

TOGAF企业架构框架-2常见术语

马说IT

架构 企业架构 TOGAF TOGAF术语

一朝见微,十年知著:联想Tiny的办公聚变

脑极体

外包学生管理系统架构设计

Jack

架构实战训练营9期

【web 开发基础】PHP 的流程控制之多向条件分支结构 -PHP 快速入门 (14)

迷彩

10月月更 PHP基础 if条件分支 多条件分支

华为云 CDN 是如何修炼 “ 内功 ” 的?

IT科技苏辞

揭开epoll面纱:Nginx,Redis等都在用的多路复用,到底是什么?

董哥的黑板报

源码 高并发 多路复用 C语言 网络

Impala基本架构

穿过生命散发芬芳

impala 10月月更

华为云CDN为什么能够打通数据传输阻碍?

路过的憨憨

华为

速度快、时延低、更安全,华为云CDN助力企业创新发展!

路过的憨憨

华为

怎么制作一份能够帮助客户的帮助文档呢?

Baklib

帮助文档

CSS学习笔记6

虾仁疙瘩汤

CSS css3 10月月更

jsp 十个常用标记回顾

你笑一下嘛!

前端 jsp 10月月更

“程”风破浪的开发者|研究生学习路程回顾

Studying_swz

学习方法 “程”风破浪的开发者

CSS基础4

虾仁疙瘩汤

CSS css3 10月月更

千锋杭州秋季IT专场双选会热烈启幕,招聘与就业成果显著

千锋IT教育

TOGAF企业架构框架-1概览

马说IT

架构 企业架构 TOGAF

网络畅通的“无名英雄”:华为云CDN,让数据传输又快又稳

路过的憨憨

华为

全国联动,千锋教育1024程序员节线下狂欢活动火热开展!

千锋IT教育

千锋HTML5大前端全网首发Web3.0面授课程,助力个人入局热门赛道!

千锋IT教育

服务巡检

芯动大师

Python 10月月更 服务巡检

上网冲浪总是慢?试试华为云CDN,高效加速真体验!

路过的憨憨

安全、快速、稳定,华为云CDN赋能中小企业数字化发展

IT科技苏辞

智慧城市、数字政府、城市大脑、一网统管之间有什么关系

雨果

智慧城市 城市大脑 数字政府 一网统管

2022-10-26:以下go语言代码输出什么?A:1 3 2;B:1 2 3;C:3 1 2;D:3 2 1。 package main import “fmt“ type temp struc

福大大架构师每日一题

golang 福大大 选择题

IoT设备与手机App之间如何实现实时消息通信——业务场景最佳实践

阿里云AIoT

物联网 IoT 传感器 智能硬件

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