一款云原生时代本地开发调试的利器-Skaffold
2020-02-14 09:23
 | 发布者: DevOps亮哥

    一、介绍

    Skaffold是一个用Go语言编写的命令行工具,能够帮助开发人员持续开发、部署Kubernetes的应用程序。开发者可以在本地环境进行代码开发,然后将修改后的代码部署到本地或远程的Kubernetes的集群环境中。Skaffold负责构建、推送和部署应用程序的工作流程,它还提供了构建块,并且描述了如何自定义CI/CD的流水线,来满足每个团队在构建、打标签和部署上的要求。

    Skaffold能够实时监控源码文件的变化,当发生变化后即可触发Skaffold配置的流水线,进行构建部署。因此,Skaffold的适用阶段为Kubernetes应用程序的本地开发调试。主要是满足本地开发阶段代码质量的检查,将问题发现和修复前移到开发阶段,这也是DevOps中的最佳实践。

    一款云原生时代本地开发调试的利器-Skaffold

    

    二、特性

    Skaffold具有以下特性:

    1、轻量级

    Skaffold只需要提供一个客户端,该客户端可以本地安装也可以使用Docker容器,支持Linux、MacOS、Windows等多个平台,不需要维护Kubernetes集群端的组件。

    Skaffold提供了一个固定阶段的、最小功能的流水线。主要阶段包括:Build、Test、Tag、Render、Deploy。

    

    2、声明式配置

    每个项目只需要提供一个skaffold.yaml配置文件,该文件描述了流水线的定义,各个阶段的声明和参数设定。

    对于新项目可以使用skaffold init命令来自动生成一个skaffold.yaml文件。当执行流水线时,Skaffold会读取这个YAML文件,根据文件的定义执行流水线任务。在流水线的不同阶段,Skaffold提供了自定义插件的功能,通过插件提供不同的实现,以满足团队不同的需求,比如Build阶段的实现有Dockerfile、Jib等。

    3、便于使用

    Skaffold的使用非常简单,只需要两步就能将项目运行起来:

    第一步:通过git clone将代码仓库克隆下来,

    第二步:进入到根目录下、执行skaffold run命令

    另外还有skaffold dev、skaffold debug等命令来满足开发阶段不同的需求。

    三、安装

    下面介绍如何在minikube的环境中安装Skaffold。

    1、Linux本地安装Skaffold

    这里介绍Linux环境下本地安装,其他还有MacOS和Windows安装,安装方式是一样的。安装的命令如下:

    curl -Lo skaffold https://storage.googleapis.com/skaffold/releases/latest/skaffold-linux-amd64 
chmod +x skaffold 
sudo mv skaffold /usr/local/bin

    Skaffold命令介绍:

    [root@learncloudnative ~]# skaffold 
A tool that facilitates continuous development for Kubernetes applications.

 Find more information at: https://skaffold.dev/docs/getting-started/

End-to-end pipelines:
 run Run a pipeline
 dev Run a pipeline in development mode
 debug [beta] Run a pipeline in debug mode

Pipeline building blocks for CI/CD:
 build Build the artifacts
 deploy Deploy pre-built artifacts
   the deployed application
 render [alpha] Perform all image builds,  output rendered Kubernetes manifests

Getting started with a new project:
 init [alpha] Generate configuration for deploying an application
 fix  old configuration to newest schema version

Other Commands:
 completion Output shell completion for the given shell (bash  zsh)
 config Interact with the Skaffold configuration
 credits Export third party notices to given path (./skaffold-credits by default)
 diagnose Run a diagnostic on Skaffold
 version Print the version information

Usage:
 skaffold [flags] [options]

Use "skaffold <command> help" for more information about a given command.
Use "skaffold options" for a list of global command-line options (applies to all commands).

    2、安装kubectl和minikube

    这个可以参考之前写过的《Jenkins X(6)虚拟机里搭建Minikube环境》文章。目前k8s的命名空间如下,后面的skaffold演示可以新建一个命名空间:skaffold-test,如果不指定命名空间默认安装到default下面。

    一款云原生时代本地开发调试的利器-Skaffold

    

    3、下载样例应用

    官方提供了一个Skaffold的演示代码库样例,可以作为入门级的演示。

    git clone https://github.com/GoogleContainerTools/skaffold 
cd examples/getting-started

    查看这个样例程序的文件结构,项目文件是main.go和README.adoc。其他是用于Skaffold执行流水线的辅助配置文件。

    [root@learncloudnative getting-started]# ll
总用量 20
-rw-rr. 1 root root 144 11月 26 17:45 Dockerfile
-rw-rr. 1 root root 153 11月 26 17:45 k8s-pod.yaml
-rw-rr. 1 root root 132 11月 27 12:21 main.go
-rw-rr. 1 root root 734 11月 26 17:45 README.adoc
-rw-rr. 1 root root 153 11月 26 17:45 skaffold.yaml

    main.go文件,一个简单go程序。可以修改该文件演示变化后的自动化流程。

    package main
import (
	"fmt"
	"time"
)
func main() {
	for {
		fmt.Println("Hello world !")
		time.Sleep(time.Second * 1)
	}
}

    Dockerfile:用于打Docker镜像的文件

    FROM golang:1.12.9-alpine3.10 as builder
COPY main.go .
RUN go build -o /app main.go

FROM alpine:3.10
CMD ["./app"]
COPY from=builder /app .

    skaffold.yaml:是Skaffold能够识别的,定义了流水线各个阶段的YAML文件。

    apiVersion: skaffold/v1
kind: Config
build:
 artifacts:
 - image: gcr.io/k8s-skaffold/skaffold-example
deploy:
 kubectl:
 manifests:
 - k8s-*

    k8s-pod.yaml:是应用程序部署到K8s集群的YAML文件。

    apiVersion: v1
kind: Pod
metadata:
 name: getting-started
spec:
 containers:
 - name: getting-started
 image: gcr.io/k8s-skaffold/skaffold-example

    四、工作流程

    一款云原生时代本地开发调试的利器-Skaffold

    

    Skaffold定义了五个阶段的工作流,每个阶段都可以单独执行,也可以全部自动化执行。在启动Skaffold后,会收集项目的源码并根据指定的构建工具进行构建,一旦构建成功,Skaffold会测试容器镜像的有效性,按照指定的标签策略打标签,并将容器进行推送到指定的镜像仓库。最后,Skaffold会自动生成manifests声明文件,将镜像制品部署到K8s 集群。也就是说,开发人员只需要对代码进行修改,剩下的工作全部交给Skaffold,就可以测试变更后的代码了。

    

    下面简单介绍这五个阶段:

    1、Build(构建)

    代码变更后,首先就要执行构建阶段,Skaffold原生支持几种不同的构建镜像的工具。比如Dockerfile、Jib Maven Gradle、Bazel、Cloud Native Buildpacks以及Custom Script。在skaffold.yaml

    2、Test(测试)

    在构建阶段构建好的镜像部署到K8s集群之前要进行验证,Skaffold支持执行container-structure-tests测试,这个测试主要验证容器镜像的结构完整性,前提是container-structure-tests的程序需要安装。

    3、Tag(标签)

    测试通过的容器镜像就可以执行打标签操作了。Skaffold支持几种不同的打标签策略,这个标签策略tagPolicy可以在skaffold.yaml文件里指定。

  • gitCommit:使用git commit ID作为标签。

  • sha256:使用sha256哈希值作为标签。

  • envTemplate:使用环境变量的值作为标签。比如 {{.RELEASE}}-{{.IMAGE_NAME}}

  • dateTime:使用时间戳作为标签。

    4、Render(渲染)

    Skaffold deployer会用打好标签的镜像名称替换Kubernetes manifests里的镜像名称,Kubernetes manifests文件就是上面的k8s-*.yaml文件。

    5、Deploy(部署)

    Skaffold deployer利用新生成的Kubernetes manifests部署到Kubernetes集群中。就可以根据变更的版本进行验证了。

    

    除了上面五个阶段外,Skaffold还提供其他附加功能,比如监控文件变化、文件同步、查看log和端口转发

    五、试用

    准备工作完成后,就可以尝试看看Skaffold是如何来辅助本地开发的。

    1、以getting-started为例

    在getting-started根目录下执行如下命令,会对源码进行构建、打标签,将服务部署到K8s集群中。

    [root@learncloudnative getting-started]# skaffold dev -n skaffold-test 
Listing files to watch...
 - gcr.io/k8s-skaffold/skaffold-example
Generating tags...
 - gcr.io/k8s-skaffold/skaffold-example -> gcr.io/k8s-skaffold/skaffold-example:v1.0.0-103-g2c03a11b-dirty
Checking cache...
 - gcr.io/k8s-skaffold/skaffold-example: Found Locally
Tags used in deployment:
 - gcr.io/k8s-skaffold/skaffold-example -> gcr.io/k8s-skaffold/skaffold-example:96b3192e1b56ab3956c96603d0f07ce14a37ae50dd4ae5133ae2b22539486f4a
 local images can't be referenced by digest. They are tagged  referenced by a unique ID instead
Starting deploy...
 - pod/getting-started created
Watching for changes...
[getting-started] Hello world !
[getting-started] Hello world !
[getting-started] Hello world !

    因为是以开发模式(dev)启动,控制台会不断输出日志,同时监测文件的变化。查看K8s集群的skaffold-test命名空间下getting-started已经部署成功。

    [root@learncloudnative ~]# kubectl get pod -n skaffold-test
NAME READY STATUS RESTARTS AGE
getting-started 1/1 Running 0 3s

    如果此时更改代码的内容,skaffold监测到文本变更后,会重新执行流水线,这里将main.go文件的输出内容改成:Hello world skaffold!!!保存后,skaffold将变更后的代码进行构建、测试、打标签,部署等。

    一款云原生时代本地开发调试的利器-Skaffold

    

    2、新项目初始化

    Skaffold需要代码库根目录下提供一个skaffold.yaml文件,对于新项目,可以使用skaffold init 初始化一个简单的配置文件,这个生成的配置文件包含build和deploy阶段,可以修改这个skaffold.yaml文件以满足自己的需求 。

    [root@learncloudnative skaffold-go-test]# skaffold init
apiVersion: skaffold/v1
kind: Config
metadata:
 name: skaffold-go-test
build:
 artifacts:
 - image: docker.io/xinglongjian/skaffold-example
deploy:
 kubectl:
 manifests:
 - k8s-pod.yaml

Do you want to write this configuration to skaffold.yaml? [y/n]: y
Configuration skaffold.yaml was written
You can now run [skaffold build] to build the artifacts
 [skaffold run] to build  deploy
 [skaffold dev] to enter development mode, with auto-redeploy

    执行下面的命令就可以进入本地开发模式。

    [root@learncloudnative skaffold-go-test]# skaffold dev -n skaffold-test
Listing files to watch...
 - docker.io/xinglongjian/skaffold-example
Generating tags...
 - docker.io/xinglongjian/skaffold-example -> docker.io/xinglongjian/skaffold-example:c3f7eb3-dirty
Checking cache...
 - docker.io/xinglongjian/skaffold-example: Not found. Building
Found [minikube] context, using local docker daemon.
Building [docker.io/xinglongjian/skaffold-example]...
Sending build context to Docker daemon 3.072kB
Step 1/6 : FROM golang:1.12.9-alpine3.10 as builder
 -> e0d646523991
Step 2/6 : COPY main.go .
 -> 075cd147a6c1
Step 3/6 : RUN go build -o /app main.go
 -> Running in 7b6467e37750
 -> 60b3cc0b274e
Step 4/6 : FROM alpine:3.10
 -> 965ea09ff2eb
Step 5/6 : CMD ["./app"]
 -> Using cache
 -> 7f97841188b2
Step 6/6 : COPY from=builder /app .
 -> 14a192c1806b
Successfully built 14a192c1806b
Successfully tagged xinglongjian/skaffold-example:c3f7eb3-dirty
Tags used in deployment:
 - docker.io/xinglongjian/skaffold-example -> docker.io/xinglongjian/skaffold-example:14a192c1806b7fe0338ccef7a7ac27243fc9e77a5e0fda8c080481f676590c23
 local images can't be referenced by digest. They are tagged  referenced by a unique ID instead
Starting deploy...
 - pod/getting-started created
Watching for changes...
[getting-started] Hello world!
[getting-started] Hello world!
[getting-started] Hello world!

    演示部分就到此为止,通过这两个例子就能了解Skaffold在本地开发Kubernetes应用程序时是多么的方便,一条命令就能将代码部署到K8s集群中,真正能做到持续开发、持续交付。

    Skaffold还提供了更多其他方便开发的功能,比如:

    1、Debug。目前支持java、go、python和node语言。

    2、IDE plugins。目前支持与VSCode和Intellij集成。

    3、Tekton。支持Tekton Pipeline的集成。

    

    六、总结

    本地开发是软件开发生命周期中非常重要的一个阶段,也是耗费时间最长的一个阶段,这个阶段的效率和质量对整个软件的交付有非常重要的影响。现在IDE的功能越来越强大,方便的操作界面,智能的代码提示提高了本地开发的效率,集成在IDE上的代码检查插件也能快速的检查代码规范等问题。

    然而,大多数问题并不是代码规范问题,而是业务逻辑问题。业务逻辑的验证需要有上下游的关联系统,目前大多数企业一般都是在代码合入后,在功能测试阶段才会涉及业务逻辑的验证。如果有问题,还需要重新修改代码,重新部署到测试环境进行验证,这样不断的重复浪费了大量的时间。如果能在本地开发阶段就能快速验证、快速反馈,将会大大提升软件交付的效率。

    

    云原生时代,软件的运行环境都是在容器上,与此同时,企业内部也需要同样的容器测试环境用于开发调试使用。因此,基于云基础设施的开发、测试、部署的软件开发流程,也会受到越来越多企业的重视,Skaffold作为基于Kubernetes应用的本地开发命令行的工具,一定会大大提升开发效率。