DockOne微信分享(一四一):如何开发部署Kubernetes Native应用

  1. 云栖社区>
  2. DockOne.io>
  3. 博客>
  4. 正文

DockOne微信分享(一四一):如何开发部署Kubernetes Native应用

猫饭先生 2017-10-10 13:55:00 浏览1007
展开阅读全文
【编者的话】当我们有了一个kubernetes集群后,如何在上面开发和部署应用,应该遵循怎样的流程?本次分享将向您展示如何使用Go语言开发和部署一个Kubernetes Native应用,使用Wercker进行持续集成与持续发布,我将以一个很简单的前后端访问,获取伪造数据并展示的例子来说明。

环境声明

本文讲的是DockOne微信分享(一四一):如何开发部署Kubernetes Native应用首先声明下我们使用的集群环境:
  • Docker 1.12.5
  • flannel network host-gw
  • Kubernetes 1.6.0
  • TLS enabled

详细的部署文档和更多资料请参考:https://github.com/rootsongjc/kubernetes-handbook

应用示例

我们的这两个示例仅仅是为了演示,开发部署一个伪造的Metric并显示在Web页面上,包括两个service:

这两个镜像可以直接从Docker Hub上下载:
  • jimmysong/k8s-app-monitor-test:latest
  • jimmysong/k8s-app-monitor-agent:latest

定义API

API文档见 https://github.com/rootsongjc/k8s-app-monitor-test 中的api.html文件,该文档在API blueprint中定义,使用aglio生成,打开后如图所示:
1.jpg

关于服务发现

K8s-app-monitor-agent服务需要访问k8s-app-monitor-test服务,这就涉及到服务发现的问题,我们在代码中直接写死了要访问的服务的内网DNS地址(kubedns中的地址,即k8s-app-monitor-test.default.svc.cluster.local)。

我们知道Kubernetes在启动Pod的时候为容器注入环境变量,这些环境变量在所有的 namespace 中共享(环境变量是不断追加的,新启动的Pod中将拥有老的Pod中所有的环境变量,而老的Pod中的环境变量不变)。但是既然使用这些环境变量就已经可以访问到对应的service,那么获取应用的地址信息,究竟是使用变量呢?还是直接使用DNS解析来发现?

答案是使用DNS,详细说明见Kubernetes中的服务发现与Docker容器间的环境变量传递源码探究

使用Wercker构建镜像

CI工具
开源项目的构建离不开CI工具,你可能经常会在很多GitHub的开源项目首页上看到这样的东西:
2.jpg

这些图标都是CI工具提供的,可以直观的看到当前的构建状态,例如Wercker中可以在Application-magpie-options中看到:
3.jpg

将文本框中的代码复制到你的项目的README文件中,就可以在项目主页上看到这样的标志了。

现在市面上有很多流行的CI/CD工具和DevOps工具有很多,这些工具提高了软件开发的效率,增加了开发人员的幸福感。这些工具有:

适用于GitHub上的开源项目,可以直接使用GitHub账户登陆,对于公开项目可以直接使用:Travis-ciCircleCIWercker。从目前GitHub上开源项目的使用情况来看,Travis-ci的使用率更高一些。

适用于企业级的:Jenkins

不仅包括CI/CD功能的DevOps平台:JFrogSpinnakerFabric8

Wercker简介
Wercker是一家为现代云服务提供容器化应用及微服务的快速开发、部署工具的初创企业,成立于2012年,总部位于荷兰阿姆斯特丹。其以容器为中心的平台可以对微服务和应用的开发进行自动化。开发者通过利用其命令行工具能够生成容器到桌面,然后自动生成应用并部署到各种云平台上面。其支持的平台包括Heroku、AWS以及Rackspace等。

Wercker于2016年获得450万美元A轮融资,此轮融资由Inkef Capital领投,Notion Capital跟投,融资所得将用于商业版产品的开发。此轮融资过后其总融资额为750万美元。

Wercker于2017年4月被Oracle甲骨文于收购。

如何使用
通过Wercker搭建CI环境只需经过三个基本步骤。
  1. 在Wercker网站中创建一个应用程序。
  2. 将wercker.yml添加到应用程序的代码库中。
  3. 选择打包和部署构建的位置。

可以使用GitHub帐号直接登录Wercker,整个创建应用CI的流程一共3步。

一旦拥有了账户,那么只需简单地点击位于顶部的应用程序菜单,然后选择创建选项即可。如果系统提示是否要创建组织或应用程序,请选择应用程序。Wercker组织允许多个Wercker用户之间进行协作,而无须提供信用卡。下图为设置新应用程序的向导页面。
4.jpg

选择了GitHub中的repo之后,第二步配置访问权限,最后一步Wercker会尝试生成一个wercker.yml文件(后面会讨论)。不过至少对于Go应用程序来说,这个配置很少会满足要求,所以我们总是需要创建自己的Wercker配置文件。

创建Wercker配置文件Wercker.Yml
Wercker配置文件是一个YAML文件,该文件必须在GitHub repo的最顶层目录,该文件主要包含三个部分,对应可用的三个主要管道。
  • Dev:定义了开发管道的步骤列表。与所有管道一样,可以选定一个box用于构建,也可以全局指定一个box应用于所有管道。box可以是Wercker内置的预制Docker镜像之一,也可以是Docker Hub托管的任何Docker镜像。
  • Build:定义了在Wercker构建期间要执行的步骤和脚本的列表。与许多其他服务(如Jenkins和TeamCity)不同,构建步骤位于代码库的配置文件中,而不是隐藏在服务配置里。
  • Deploy:在这里可以定义构建的部署方式和位置。

Wercker中还有工作流的概念,通过使用分支、条件构建、多个部署目标和其他高级功能扩展了管道的功能,这些高级功能读着可以自己在wercker的网站中探索。

因为我使用Wercker自动构建,构建完成后自动打包成Docker镜像并上传到Docker Hub中(需要先在Docker Hub中创建repo),如何使用Wercker做持续构建与发布,并集成Docker Hub插件请参考:https://jimmysong.io/blogs/con ... cker/

K8s-app-monitor-agent的Wercker配置文件如下:
yaml
box: golang

build:

steps:
- setup-go-workspace

- script:
    name: go get
    code: |
      cd $WERCKER_SOURCE_DIR
      go version
      go get -u github.com/Masterminds/glide
      export PATH=$WERCKER_SOURCE_DIR/bin:$PATH
      glide install
# Build the project
- script:
    name: go build
    code: |
      go build
- script:
    name: copy files to wercker output 
    code: |
      cp -R ./ ${WERCKER_OUTPUT_DIR}
deploy:
steps:
- internal/docker-push:
   username: $USERNAME
   password: $PASSWORD
   cmd: /pipeline/source/k8s-app-monitor-agent
   port: "3000"
   tag: latest
   repository: jimmysong/k8s-app-monitor-agent

其中的$USERNAME$PASSWORD是Docker Hub的用户名和密码,这些是做作为Wercker构建的环境变量,在Wercker的Web端进行配置的。

此文件包含两个管道:build和deploy。在开发流程中,我们使用Wercker和Docker创建一个干净的Docker镜像,然后将它push到Docker Hub中。Wercker包含一个叫做Internal/docker-push的deploy plugin,可以将构建好的Docker镜像push到镜像仓库中,默认是Docker Hub,也可以配置成私有镜像仓库。

box键的值是Golang。这意味着我们使用的是一个基础的Docker镜像,它已经安装了Go环境。这一点至关重要,因为执行Wercker构建的基准Docker镜像需要包含应用程序所需的构建工具。

构建流程见:https://app.wercker.com/jimmys ... gent/

当然你还可以使用其他的CI工具,因为Wercker的插件比较方便,可以直接构建成Docker镜像上传到Docker Hub中,比较方便,所以我选择了Wercker。
生成了如下两个Docker镜像:
  • jimmysong/k8s-app-monitor-test:latest
  • jimmysong/k8s-app-monitor-agent:latest

启动服务

所有的Kubernetes应用启动所用的yaml配置文件都保存在那两个GitHub仓库的manifest.yaml文件中。

比如k8s-app-monitor-agentmanifest.yaml文件如下:
Yaml
apiVersion: extensions/v1beta1
kind: Deployment
metadata:
name: k8s-app-monitor-agent
namespace: default
spec:
replicas: 1
template:
metadata:
  labels:
    k8s-app: k8s-app-monitor-agent
spec:
  containers:
  - image: jimmysong/k8s-app-monitor-agent:latest
    imagePullPolicy: Always
    name: app
    ports:
    - containerPort: 8080
    env: 
    - name: APP_PORT
      value: "3000"
    - name: SERVICE_NAME
      value: "k8s-app-monitor-test"
---
apiVersion: v1
kind: Service
metadata:
name: k8s-app-monitor-agent
labels:
k8s-svc: k8s-app-monitor-agent
spec:
ports:
- port: 8080
protocol: TCP
name: http
selector:
k8s-app: k8s-app-monitor-agent

注意其中的env,包括了两个环境变量(注意:环境变量名称必须为大写字母):APP_PORTSERVICE_NAME,这两个环境变量,在 main.go的代码中我们可以看到:
Go
func drawChart(res http.ResponseWriter, req *http.Request) {
port := os.Getenv("APP_PORT")
service := os.Getenv("SERVICE_NAME")
if len(port) == 0 {
    port = "3000"
}
if len(service) == 0 {
    service = "localhost"
} 

如果程序启动的时候找不到该环境变量,将会使用程序内置的默认值,当然我们不该将服务地址写死在程序内部,而应该是可配置的,在Kubernetes中最佳配置方式是环境变量或者ConfigMap。

分别在两个GitHub目录下执行kubectl create -f manifest.yaml即可启动服务。

外部访问
服务启动后需要更新Ingress配置,在ingress.yaml文件中增加以下几行:
yaml
- host: k8s-app-monitor-agent.jimmysong.io
http:
  paths:
  - path: /
    backend:
      serviceName: k8s-app-monitor-agent
      servicePort: 8080 

保存后,然后执行kubectl replace -f ingress.yaml即可刷新Ingress。

修改本机的/etc/hosts文件,在其中加入以下一行:
172.20.0.119 k8s-app-monitor-agent.jimmysong.io

当然你也可以加入到DNS中,为了简单起见我使用hosts。

在浏览器中访问http://k8s-app-monitor-agent.jimmysong.io
5.jpg

刷新页面将获得新的图表。

边缘节点配置
边缘节点架构图:
6.png

选择Kubernetes的三个node作为边缘节点,并安装Keepalived,上图展示了边缘节点的配置,同时展示了向Kubernetes中添加服务的过程。

边缘节点定义

首先解释下什么叫边缘节点(Edge Node),所谓的边缘节点即集群内部用来向集群外暴露服务能力的节点,集群外部的服务通过该节点来调用集群内部的服务,边缘节点是集群内外交流的一个Endpoint。

边缘节点要考虑两个问题
  • 边缘节点的高可用,不能有单点故障,否则整个kubernetes集群将不可用
  • 对外的一致暴露端口,即只能有一个外网访问IP和端口

为了满足边缘节点的以上需求,我们使用Keepalived来实现。

在Kubernetes中添加了service的同时,在DNS中增加一个记录,这条记录需要跟ingress中的host字段相同,IP地址即VIP的地址,本示例中是172.20.0.119,这样集群外部就可以通过service的DNS名称来访问服务了。

详细操作步骤和配置请参考:https://github.com/rootsongjc/ ... on.md

参考


以上内容根据2017年09月14日晚微信群分享内容整理。 分享人宋净超,容器技术负责人,Kubernetes社区专家作者。曾就职于科大讯飞,在大数据平台架构与优化、云平台的开发与维护方面拥有丰富经验,目前在TalkingData从事kubernetes和云原生应用的研究和推广工作。Cloud Native Go 图书译者之一、Qcon、CNUTcon讲师,个人博客 http://jimmysong.io DockOne每周都会组织定向的技术分享,欢迎感兴趣的同学加微信:liyingjiesa,进群参与,您有想听的话题或者想分享的话题都可以给我们留言。

原文发布时间为:2017-09-19

本文作者:尼古拉斯

本文来自云栖社区合作伙伴Dockerone.io,了解相关信息可以关注Dockerone.io。

原文标题:DockOne微信分享(一四一):如何开发部署Kubernetes Native应用

网友评论

登录后评论
0/500
评论
猫饭先生
+ 关注
所属云栖号: DockOne.io