本文介绍在开发过程中,Skaffold自动化build和deploy应用到K8S集群。
Skaffold是由Google发布的命令行工具,专注于促进K8S应用的持续deployment。自动化building和deploying到k8s集群的任务,可以让开发者专注于编写代码。Skaffold是不是很有趣呢,让我们来仔细观察一下吧。
简介
2019年11月份,Skaffold普遍可用的版本发布了,承诺自动化开发工作流程,以此来节省开发者的时间。那么,Skaffold提供哪些功能呢?
当你开发的时候,检测代码的变动
基于你的Dockerfile或者Jib自动化build和创建你的artifacts(也就是Docker image)
给artifacts打tag
把artifacts发布/部署到你的kubernetes集群
为了熟悉Skaffold,我们使用minikube来运行一个本地的K8S集群,部署K8S的命令行工具kubectl。
更深入了解Skaffold,建议读者去官方网站去查看文档和例子。本文使用的源代码都在github是可见的。
先决条件
开始之前,我们需要安装minikube,kubectl和Skaffold,OS版本是Ubuntu 18.04
安装Minikube
Minikube(1.6.2)的安装工作在Linux上非常简单。如果使用Windows操作系统,请查询我们的过往文章,操作步骤还是非常复杂,未来可能会有所改善。
首先,检查我们的OS是否开启了虚拟化支持
$ egrep -q 'vmx|svm' /proc/cpuinfo && echo yes || echo no
yes
命令的输出是yes,我们不需要额外执行命令了。
下载并安装minikube
$ curl -LO https://storage.googleapis.com/minikube/releases/latest/minikube_1.6.2.deb && sudo dpkg -i minikube_1.6.2.deb
启动minikube
$ minikube start
minikube v1.6.2 on Ubuntu 18.04Automatically selected the 'virtualbox' driver (alternates: [none])Downloading VM boot image ...> minikube-v1.6.0.iso.sha256: 65 B / 65 B [--------------] 100.00% ? p/s 0s> minikube-v1.6.0.iso: 150.93 MiB / 150.93 MiB [-] 100.00% 8.44 MiB p/s 18sCreating virtualbox VM (CPUs=2, Memory=2000MB, Disk=20000MB) ...Preparing Kubernetes v1.17.0 on Docker '19.03.5' ...Downloading kubelet v1.17.0Downloading kubeadm v1.17.0Pulling images ...Launching Kubernetes ...Waiting for cluster to come online ...Done! kubectl is now configured to use "minikube"
安装Kubectl
Kubectl的安装手册可以在kubernetes官网查看。对于LinuxOS,我们需要执行下面的步骤,使用kubectl version命令可以确认是否安装成功。
$ curl -LO https://storage.googleapis.com/kubernetes-release/release/`curl -s https://storage.googleapis.com/kubernetes-release/release/stable.txt`/bin/linux/amd64/kubectl
$ chmod +x ./kubectl
$ sudo mv ./kubectl /usr/local/bin/kubectl
$ kubectl version
Client Version: version.Info{Major:"1", Minor:"17", GitVersion:"v1.17.0", GitCommit:"70132b0f130acc0bed193d9ba59dd186f0e634cf", GitTreeState:"clean", BuildDate:"2019-12-07T21:20:10Z", GoVersion:"go1.13.4", Compiler:"gc", Platform:"linux/amd64"}Server Version: version.Info{Major:"1", Minor:"17", GitVersion:"v1.17.0", GitCommit:"70132b0f130acc0bed193d9ba59dd186f0e634cf", GitTreeState:"clean", BuildDate:"2019-12-07T21:12:17Z", GoVersion:"go1.13.4", Compiler:"gc", Platform:"linux/amd64"}
安装Skaffold
Skaffold的安装文档可以在官网查看。安装方法非常和kubectl非常类似。
$ curl -Lo skaffold https://storage.googleapis.com/skaffold/releases/latest/skaffold-linux-amd64
$ chmod +x skaffold
$ sudo mv skaffold /usr/local/bin
$ skaffold version
v1.1.0
创建Demo应用
我们将会创建一个简单的Spring Boot demo应用。我们使用Spring MVC,创建一个REST endpoint,将会返回一个欢迎信息。
我们的Pom包含了下面的依赖关系和插件
<dependencies><dependency><groupId>org.springframework.boot</groupId><artifactId>spring-boot-starter-actuator</artifactId></dependency><dependency><groupId>org.springframework.boot</groupId><artifactId>spring-boot-starter-web</artifactId></dependency><dependency><groupId>org.springframework.boot</groupId><artifactId>spring-boot-starter-test</artifactId><scope>test</scope></dependency></dependencies><build><plugins><plugin><groupId>org.springframework.boot</groupId><artifactId>spring-boot-maven-plugin</artifactId></plugin></plugins></build>
@RestControllerpublic class HelloController {@RequestMapping("/hello")public String hello() {StringBuilder message = new StringBuilder("Hello Skaffold!");try {InetAddress ip = InetAddress.getLocalHost();
message.append(" From host: " + ip);} catch (UnknownHostException e) {
e.printStackTrace();}return message.toString();}}
使用Skaffold
现在我们已经完成了所有的准备,是时候开始使用Skaffold了。现在,我们故意遗漏一些Skaffold需要的重要配置,这可以让我们来检查报错信息和解决方法。
生成skaffold.yaml
Skaffold需要一个skaffold.yaml文件,包含你需要使用的开发工作流程。可以在你的项目目录里使用init命令来自动生成。
$ skaffold init
FATA[0000] one or more valid Kubernetes manifests is required to run skaffold
Skaffold init并不会为我们创建k8s的mainfest文件,我们需要手动创建。
我们将会使用kubectl工具来创建k8s的部署文件。我们把Kubectl命令的输出复制到deployment.yaml文件中。命令行参数 –dry-run 可以确保部署并没有被执行, -oyaml参数会输出配置文件,我们可以从中复制内容。
$ kubectl create deployment myskaffoldplanet --image=docker.io/mydeveloperplanet/myskaffoldplanet --dry-run -oyaml
apiVersion: apps/v1
kind: Deployment
metadata:
creationTimestamp: null
labels:
app: myskaffoldplanet
name: myskaffoldplanet
spec:
replicas: 1
selector:
matchLabels:
app: myskaffoldplanet
strategy: {}template:
metadata:
creationTimestamp: null
labels:
app: myskaffoldplanet
spec:
containers:- image: docker.io/mydeveloperplanet/myskaffoldplanet
name: myskaffoldplanet
resources: {}
status: {}
再次执行skaffold init命令,返回新的错误
$ skaffold init
FATA[0000] one or more valid builder configuration (Dockerfile or Jib configuration) must be present to build images with skaffold; please provide at least one build config and try again or run `skaffold init --skip-build`
上面的报错是可以预见的,因为我们并没有提供Dockerfile或者Jib配置。使用我们在之前的文章中提到的方法,我们使用Jib。添加Jib Maven插件到我们的pom中。这一次我们不提供认证,因为我们并不会把docker镜像提交给docker仓库。
<plugin><groupId>com.google.cloud.tools</groupId><artifactId>jib-maven-plugin</artifactId><version>1.8.0</version><configuration><!-- openjdk:11.0.5-jre --><from><image>openjdk@sha256:b3e19d27caa8249aad6f90c6e987943d03e915bbf3a66bc1b7f994a4fed668f6</image></from><to><image>docker.io/${docker.image.prefix}/${project.artifactId}</image><tags><tag>${project.version}</tag></tags></to><container><mainClass>com.mydeveloperplanet.myskaffoldplanet.MySkaffoldPlanetApplication</mainClass><user>nobody</user></container></configuration></plugin>
为了使用Jib,我们需要在skaffold命令中加入参数:–XxenableJibInit
$ skaffold init --XXenableJibInit
apiVersion: skaffold/v2alpha1
kind: Config
metadata:
name: myskaffoldplanet
build:
artifacts:- image: docker.io/mydeveloperplanet/myskaffoldplanet
jib: {}
deploy:
kubectl:
manifests:- k8s/deployment.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
or [skaffold run] to build and deploy
or [skaffold dev] to enter development mode, with auto-redeploy
Skaffold持续发布
为了配合skaffold dev命令做实验,我们已经做好了所有配置。这将会扫描我们的项目,一旦有变更,便会自动build和部署到我们的K8S集群中。执行下面的命令
$ skaffold dev
我们的应用正在被build部署到K8S集群中。操作可以在minikube的dashboard里观察。
minikube dashboard
因为并没有创建service的缘故,现在还不能调用我们的URL。我们通过NodePort方式映射端口8080。使用kubectl命令生成service yaml文件,复制内容(忽略label)到文件service.yaml到k8s的目录:
$ kubectl expose deployment myskaffoldplanet --type=NodePort --port=8080 --dry-run -oyaml
apiVersion: v1
kind: Service
metadata:
creationTimestamp: null
labels:
app: myskaffoldplanet
app.kubernetes.io/managed-by: skaffold-v1.1.0
skaffold.dev/builder: local
skaffold.dev/cleanup: "true"
skaffold.dev/deployer: kubectl
skaffold.dev/docker-api-version: "1.40"
skaffold.dev/run-id: c8fc23d2-85f5-453a-bc22-19f4a9ec88a6
skaffold.dev/tag-policy: git-commit
skaffold.dev/tail: "true"
name: myskaffoldplanet
spec:
ports:- port: 8080
protocol: TCP
targetPort: 8080
selector:
app: myskaffoldplanet
type: NodePort
status:
loadBalancer: {}
还有,把service.yaml文件作为mainfest文件添加到skaffold.yaml文件:
deploy:
kubectl:
manifests:- k8s/deployment.yaml
- k8s/service.yaml
Skaffold会迅速观察到这些变化,自动创建服务。可以在Skaffold console输出中得到确认:
Starting deploy...- deployment.apps/myskaffoldplanet configured
- service/myskaffoldplanet created
Watching for changes...
使用Kubectl来确认服务已经被创建:
$ kubectl get services
NAME TYPE CLUSTER-IP EXTERNAL-IP PORT(S) AGE
kubernetes ClusterIP 10.96.0.1 443/TCP 24h
myskaffoldplanet NodePort 10.96.65.87 8080:30272/TCP 42s
NodePort已经被分配给30272端口。我们现在可以引用我们的Rest endpoint:
$ curl $(minikube ip):30272/hello
Hello Skaffold! From host: myskaffoldplanet-76f44959c9-tcvw5/172.17.0.6
在HelloController中修改欢迎致辞:
StringBuilder message = new StringBuilder(“Hello there, Skaffold!”);
再一次地,改动自动被Skaffold识别,后台进程中,我们的应用正在被build和部署。我们再一次调用URL:
$ curl $(minikube ip):30272/hello
Hello there, Skaffold! From host: myskaffoldplanet-54b59fb785-hczn8/172.17.0.7
我们也可以使用skaffold up命令来基于需求部署应用:
$ skaffold run
...Starting deploy...- deployment.apps/myskaffoldplanet created
- service/myskaffoldplanet created
You can also run [skaffold run --tail] to get the logs
Troubleshooting
之前执行skaffold dev和skaffold run命令遇到的报错如下:
rpc error: code = Unknown desc = Error response from daemon: pull access denied for mydeveloperplanet/myskaffoldplanet, repository does not exist or may require 'docker login': denied: requested access to the resource is denied
解决方案:把下面的内容加入到skaffold.yaml文件。
build:local:
push: false
artifacts:- image: docker.io/mydeveloperplanet/myskaffoldplanet
jib: {}
结论
本文中,我们观察了开发环境中Skaffold自动build和部署应用给K8S集群的过程。本文的内容仅仅是稍微观察Skaffold提供的功能,但是skaffold确实让人印象深刻。Skaffold绝对是值得使用和后续观察的。
译者:李原
原文链接:https://dzone.com/articles/skaffold-k8s-development-made-easy