K8S部署方式选择——没有最好的,只有最合适的
Together for a Shared future
一起向未来
前言
前面几篇文章讲解了K8S相关的基础知识,但是忘记说了应该怎么去部署K8S的相关组件和服务。今天利用这篇文章补充下。
先不考虑K8S的方式,先考虑下在CentOS下我们是如何安装软件的,常规的方式其实就是两种:
-
下载tar包使用命令:tar -zxvf xxxx.tar来进行解压安装,并配置相关的环境变量,修改相关的系统参数来完成软件的安装。 -
使用centos自带的yum(rpm)进行安装,当你在使用tar命令进行一顿安装配置的时候,一个yum install xxxx可能会让你感觉整个世界都美好了。
上面两种方式对应的就是手动安装和自动安装。无独有偶,K8S中也有同样的安装方式:
-
编写各种yaml文件,使用kubectl -f xxxx.yaml命令来进行K8S应用的部署和管理。 -
将各种依赖的yaml文件进行编排,封装成K8S的chart,使用helm命令进行服务的部署和管理,命令也是类似于centos的helm install xxxx等。
那么问题来了,对于初学者或者刚上手的人,到底该怎么选择呢?下面我们分别来讲一下这两种方式的特点。
正文
kubectl命令
前面的例子绝大数都是使用kubectl命令来创建和管理K8S组件的,其实就是通过yaml文件来进行编排的。这样做的好处很明显,那就是逻辑清晰,便于扩展和修改。
这对于逻辑简单的应用来说是个很好的选择,毕竟只需要写一个deployment或者一个deployment+一个service即可。
这里kubectl命令就不过多说明了,最后说一下kubectl命令最常用的两个命令create和apply的区别吧:
-
kubectl create -f xxx.yaml:先删除yaml上所有的组件,然后重新根据yaml文件生成新的组件。所以要求yaml文件中的配置必须是完整的。 -
kubectl apply -f xxx.yaml:根据配置文件里面列出来的内容,找到增量的更新内容,然后对更新内容升级现有的组件。所以yaml文件的内容可以只写需要升级的属性。
所以,当配置文件是完整的时候,create和apply除了执行效率不同外,执行效果效果几乎相同。
helm
虽然kubectl命令控制起来比较方便,也便于理解,但是当你要构建一个复杂的组件,比如nosql数据库时,直接使用yaml文件直接写会十分的繁琐且复杂,上手的门槛也很高。
下面的图就是对elasticsearch在k8s上yaml编排的文件目录,这还没考虑到很多非必要的配置就已经如此多的yaml文件了,更不用说如果出问题该如何调试了。
看到这些yaml文件估计绝大多数初学者就已经望而却步了,而直接使用kubectl命令带来的弊端也同样暴露了出来:
-
如何将这些yaml作为一个整体管理 -
这些yaml文件如何高效复用 -
不支持应用级别的版本管理
为了解决上述的问题,K8S推出了Helm来对chart进行管理,以达到yum在centos中所起到的作用。下面我们就来看看Helm是怎么玩的?
首先先说明下,Helm跟随着K8S的版本升级,经历了Helm2和Helm3两个版本。两者最大的差别就是Helm2有一个server端Tiller,而Helm3移除了Tiller。差别产生的原因是因为开发Helm2时,由于K8S没有基于角色的访问控制(RBAC),Helm不得不自己控制权限以及在哪里能够安装应用。直到K8S 1.6中开启了RBAC ,这件事就变得简单了。Helm也不必再做重复的事情,因此Helm3彻底移除了Tiller。
所以如果是新版本的K8S,建议直接使用Helm3。另外现在网上Helm的资料很多都是Helm2版本的,导致在Helm3上无法使用。作者曾纠结于为什么网上很普通的helm init命令总是提示命令找不到,后来才知道是版本的锅。所以在查资料的时候一定要确定好版本。一般来说,过滤资料中是否有Tiller会是一个很好的方法。
下面我们直接来直接创建一个demo来了解下helm的工作机制:
首先使用helm创建一个新的chart:
创建完毕后,就会在当前目录下创建了一个chart名称的文件夹,进入文件夹,看看目录结构:
使用tree命令看下目录的树结构:
下面针对树结构对各个文件夹以及文件的作用进行描述:
# tree everisk
everisk
├── Chart.yaml # Chart元数据信息,包含名称、版本等
├── charts # 依赖Chart集合: 一些应用的Helm chart有多个额外的chart或者subchart,需要与主要的应用程序一起部署;当这种情况发生时,value文件将用每个chart的value进行更新,这样应用程序将会同时配置和部署
├── templates # K8S资源模板集合[运维人员写的配置文件模板]
│ ├── NOTES.txt # 创建后空文件,可以手动编辑以及编写,在安装Chart时自动显示的用户帮助文档,通常会包含该Chart的使用和配置方法
│ ├── _helpers.tpl # 定义一些可以在Chart里引用的Yaml内容片段
│ ├── deployment.yaml # 用来创建Deployment的资源描述示例
│ ├── hpa.yaml # 用来创建hpa的资源描述示例
│ ├── ingress.yaml # 用来创建ingress的资源描述示例
│ ├── service.yaml # 用来创建service的资源描述示例
│ ├── serviceaccount.yaml # 用来创建serviceaccount的资源描述示例
│ └── tests # 测试目录
│ └── test-connection.yaml # 连接到应用程序的测试
└── values.yaml # 参数配置模板[开发人员写的可选配置参数],与templates文件夹中的各种资源模板进行联动,共同生成chart包
3 directories, 10 files
Helm中有两个重要的入口,一个就是Chart.yaml,另外一个就是values.yaml,这两个配置文件里面的配置项会在模板中被引用,所有的编排以及配置入口也主要是这两个文件。
模板文件的设置格式可以从values.yaml文件中收集部署信息,故当自定义helm chart时,需要配置values.yaml文件
# Default values for everisk.
# This is a YAML-formatted file.
# Declare variables to be passed into your templates.
replicaCount: 1
image:
repository: 172.16.36.145/bangcle/webservice
pullPolicy: Always
# Overrides the image tag whose default is the chart appVersion.
tag: ""
imagePullSecrets: []
nameOverride: ""
fullnameOverride: ""
serviceAccount:
# Specifies whether a service account should be created
create: false
# Annotations to add to the service account
annotations: {}
# The name of the service account to use.
# If not set and create is true, a name is generated using the fullname template
name: ""
podAnnotations: {}
podSecurityContext: {}
# fsGroup: 2000
securityContext: {}
# capabilities:
# drop:
# - ALL
# readOnlyRootFilesystem: true
# runAsNonRoot: true
# runAsUser: 1000
service:
type: ClusterIP
port: 9990
ingress:
enabled: false
annotations: {}
# kubernetes.io/ingress.class: nginx
# kubernetes.io/tls-acme: "true"
hosts:
- host: chart-example.local
paths: []
tls: []
# - secretName: chart-example-tls
# hosts:
# - chart-example.local
resources: {}
# We usually recommend not to specify default resources and to leave this as a conscious
# choice for the user. This also increases chances charts run on environments with little
# resources, such as Minikube. If you do want to specify resources, uncomment the following
# lines, adjust them as necessary, and remove the curly braces after 'resources:'.
# limits:
# cpu: 100m
# memory: 128Mi
# requests:
# cpu: 100m
# memory: 128Mi
autoscaling:
enabled: false
minReplicas: 1
maxReplicas: 100
targetCPUUtilizationPercentage: 80
# targetMemoryUtilizationPercentage: 80
nodeSelector: {}
tolerations: []
affinity: {}
再看来看看deployment模板相关的内容:
apiVersion: apps/v1
kind: Deployment
metadata:
name: {{ include "everisk.fullname" . }}
labels:
{{- include "everisk.labels" . | nindent 4 }}
spec:
{{- if not .Values.autoscaling.enabled }}
replicas: {{ .Values.replicaCount }}
{{- end }}
selector:
matchLabels:
{{- include "everisk.selectorLabels" . | nindent 6 }}
template:
metadata:
{{- with .Values.podAnnotations }}
annotations:
{{- toYaml . | nindent 8 }}
{{- end }}
labels:
{{- include "everisk.selectorLabels" . | nindent 8 }}
spec:
{{- with .Values.imagePullSecrets }}
imagePullSecrets:
{{- toYaml . | nindent 8 }}
{{- end }}
serviceAccountName: {{ include "everisk.serviceAccountName" . }}
securityContext:
{{- toYaml .Values.podSecurityContext | nindent 8 }}
containers:
- name: {{ .Chart.Name }}
securityContext:
{{- toYaml .Values.securityContext | nindent 12 }}
image: "{{ .Values.image.repository }}:{{ .Values.image.tag | default .Chart.AppVersion }}"
imagePullPolicy: {{ .Values.image.pullPolicy }}
ports:
- name: http
containerPort: 80
protocol: TCP
livenessProbe:
httpGet:
path: /
port: http
readinessProbe:
httpGet:
path: /
port: http
resources:
{{- toYaml .Values.resources | nindent 12 }}
{{- with .Values.nodeSelector }}
nodeSelector:
{{- toYaml . | nindent 8 }}
{{- end }}
{{- with .Values.affinity }}
affinity:
{{- toYaml . | nindent 8 }}
{{- end }}
{{- with .Values.tolerations }}
tolerations:
{{- toYaml . | nindent 8 }}
{{- end }}
文件都是helm相关的函数,绝大部分都是从values.yaml中获取属性,最后生成完整的deployment.yaml文件。仔细看image属性中有Chart的依赖,所以需要对Chart.yaml的相关内容进行编辑:
apiVersion: v2
name: everisk
description: A Helm chart for Kubernetes
# A chart can be either an 'application' or a 'library' chart.
#
# Application charts are a collection of templates that can be packaged into versioned archives
# to be deployed.
#
# Library charts provide useful utilities or functions for the chart developer. They're included as
# a dependency of application charts to inject those utilities and functions into the rendering
# pipeline. Library charts do not define any templates and therefore cannot be deployed.
type: application
# This is the chart version. This version number should be incremented each time you make changes
# to the chart and its templates, including the app version.
# Versions are expected to follow Semantic Versioning (https://semver.org/)
version: 0.1.0
# This is the version number of the application being deployed. This version number should be
# incremented each time you make changes to the application. Versions are not expected to
# follow Semantic Versioning. They should reflect the version the application is using.
appVersion: ver4.8.9.4_EVERSK_rel_220104.1
appVersion会成为deployment中iamge属性的版本信息,这里修改成对应包的版本信息。
万事俱备后,就到了看看我们之前一顿操作的成果,使用下面的命令可以达到预览的效果:helm install --dry-run web everisk/
真的是dry-run啊,翻译过来可以用一句我们那边的方言:干拉来描述,看看干拉的效果:
NAME: web
LAST DEPLOYED: Thu Feb 17 10:57:20 2022
NAMESPACE: default
STATUS: pending-install
REVISION: 1
HOOKS:
---
# Source: everisk/templates/tests/test-connection.yaml
apiVersion: v1
kind: Pod
metadata:
name: "web-everisk-test-connection"
labels:
helm.sh/chart: everisk-0.1.0
app.kubernetes.io/name: everisk
app.kubernetes.io/instance: web
app.kubernetes.io/version: "ver4.8.9.4_EVERSK_rel_220104.1"
app.kubernetes.io/managed-by: Helm
annotations:
"helm.sh/hook": test-success
spec:
containers:
- name: wget
image: busybox
command: ['wget']
args: ['web-everisk:9990']
restartPolicy: Never
MANIFEST:
---
# Source: everisk/templates/service.yaml
apiVersion: v1
kind: Service
metadata:
name: web-everisk
labels:
helm.sh/chart: everisk-0.1.0
app.kubernetes.io/name: everisk
app.kubernetes.io/instance: web
app.kubernetes.io/version: "ver4.8.9.4_EVERSK_rel_220104.1"
app.kubernetes.io/managed-by: Helm
spec:
type: ClusterIP
ports:
- port: 9990
targetPort: http
protocol: TCP
name: http
selector:
app.kubernetes.io/name: everisk
app.kubernetes.io/instance: web
---
# Source: everisk/templates/deployment.yaml
apiVersion: apps/v1
kind: Deployment
metadata:
name: web-everisk
labels:
helm.sh/chart: everisk-0.1.0
app.kubernetes.io/name: everisk
app.kubernetes.io/instance: web
app.kubernetes.io/version: "ver4.8.9.4_EVERSK_rel_220104.1"
app.kubernetes.io/managed-by: Helm
spec:
replicas: 1
selector:
matchLabels:
app.kubernetes.io/name: everisk
app.kubernetes.io/instance: web
template:
metadata:
labels:
app.kubernetes.io/name: everisk
app.kubernetes.io/instance: web
spec:
serviceAccountName: default
securityContext:
{}
containers:
- name: everisk
securityContext:
{}
image: "172.16.36.145/bangcle/webservice:ver4.8.9.4_EVERSK_rel_220104.1"
imagePullPolicy: Always
ports:
- name: http
containerPort: 80
protocol: TCP
livenessProbe:
httpGet:
path: /
port: http
readinessProbe:
httpGet:
path: /
port: http
resources:
{}
NOTES:
1. Get the application URL by running these commands:
export POD_NAME=$(kubectl get pods --namespace default -l "app.kubernetes.io/name=everisk,app.kubernetes.io/instance=web" -o jsonpath="{.items[0].metadata.name}")
echo "Visit http://127.0.0.1:8080 to use your application"
kubectl --namespace default port-forward $POD_NAME 8080:80
可以看看效果是否符合预期,如果不符合,再根据问题在两个配置文件中进行相应的适配即可。
最后总结下Helm的作用,主要体现在基础运维建设及业务应用两方面:
-
基础运维建设:更方便地部署与升级基础设施,如gitlab,prometheus,grafana,ES等,可以直接通过helm install直接安装使用,降低了这些复杂组件的部署和管理门槛,使得部署和管理过程对用户透明。 -
业务应用:更方便地部署,管理与升级公司内部应用,为公司内部的项目配置Chart,使用Helm结合CI/CD,在k8s中部署应用如一行命令般简单
总结
上面描述了K8S的两种部署方式,各有各的特点以及使用场景,大家可以根据需求进行选择。但是对于新手来说下面的规则值得借鉴:
-
对于复杂的成熟的基础组件,建议使用Helm直接安装,降低使用门槛 -
对于简单的业务模块,建议直接使用kubectl命令进行管理,方便直观且上手简单 -
对于复杂的业务模块,尤其是业务逻辑复杂以及依赖关系复杂的场景,则可以根据实际情况来定,一个好的方案是前期使用kubectl命令进行管理,后期慢慢过渡到helm chart的模式,毕竟Helm的管理更专业且方便,能更好的和其他功能配合和协作
最后再说一句,Helm的内容还是比较多的,网上的培训资料也很多,动辄就二三十节课,学习成本还是很高的,建议大家不必过于纠结于此,暂时先放一下,会安装基础的公共组件即可。先集中力量解决主要问题和矛盾,等有时间和精力再来仔细研究。
作者也是简单的了解了下原理就没有继续深入了,所以详细的例子暂时不能提供,后续找机会再补上吧,这个应该不会耽误大家学习K8S。
最后,如果想一起入门学习K8S的小伙伴,欢迎点赞转发加关注,下次学习不迷路!
点个在看你最好看