我们上文中有讲过怎么遍历对象和数组,但是没有具体的讲怎么使用,现在教程来了。
#values.yaml文件定义
#资源占用,若不需要,直接写{}
requests:
cpu: 500m
是怎么引用的
apiVersion: apps/v1
kind: Deployment
metadata:
...省略
spec:
...省略
template:
...省略
spec:
containers:
- name: {
{
.Values.project }}-{
{
.Values.appName }}
...省略
resources:
requests: #看下面这一行
{
{
range $key, $val := .Values.requests }}{
{
$key }}: {
{
$val | quote }}{
{
- end}}
volumeMounts:
...省略
数组和对象的差别就是,数组是并列的没有key的,对象都是有key的。
#values.yaml文件定义
#数组定义,
volumeMounts:
- mountPath: /data/www
name: data-www
- mountPath: /data/www1
name: data-www1
是怎么引用的
apiVersion: apps/v1
kind: Deployment
metadata:
...省略
spec:
...省略
template:
...省略
spec:
containers:
- name: {
{ .Values.project }}-{
{ .Values.appName }}
...省略
resources:
requests:
{
{ range $key, $val := .Values.requests }}{
{ $key }}: {
{ $val | quote }}{
{- end}}
volumeMounts:#看下面这几行
{
{- range .Values.volumeMounts }}
-{
{- range $key, $val := . }}
{
{ $key }}: {
{ $val | quote }}
{
{- end}}
{
{- end}}
volumes:
- name: data-www
persistentVolumeClaim:
claimName: oss-{
{ .Values.project }}-{
{ .Values.appName }}-pvc
- name: data-www1
hostPath:
path: /data/logs # 物理节点上的真实路径
type: Directory # 如果该路径不存在讲如何处理,Directory是要求目录必须存在,也可以不写
#执行的命令
commandArgs:
- |
rm -f /etc/nginx/sites-enabled/default.conf
rm -f /etc/nginx/sites-available/*.conf
cp /data/www/ebeikeApi.conf /etc/nginx/sites-enabled/
cp /data/www/php-ext-conf.ini /usr/local/etc/php/conf.d/
mkdir -p /var/www/html/
unzip /data/www/code/ebeikeApi.zip -d /var/www/html/
mkdir -p /data/logs/nginx
chmod -R 777 /var/www/html/ /data/logs
php-fpm -y /usr/local/etc/php-fpm.d/www.conf -D
/usr/sbin/nginx -g 'daemon off;'
怎么引用的
apiVersion: apps/v1
kind: Deployment
metadata:
...省略
spec:
...省略
template:
metadata:
...省略
spec:
containers:
- name: {
{ .Values.project }}-{
{ .Values.appName }}
...省略
resources:
requests:
{
{ range $key, $val := .Values.requests }}{
{ $key }}: {
{ $val | quote }}{
{- end}}
volumeMounts:
{
{- range .Values.volumeMounts }}
-{
{- range $key, $val := . }}
{
{ $key }}: {
{ $val | quote }}
{
{- end}}
{
{- end}}
command: ["/bin/sh","-c"]
args: #看下面这一行
- {
{ range .Values.commandArgs }} {
{ . | quote }}{
{ end }}
volumes:
...省略
特别提示:“-|” 这个符号其实是两部分,“-”是代表数组,“|”竖线,代表下面的这些行都是一个字符串。如果不懂,请参考下面的方法,转成json查看就懂了。
对yaml不熟悉的时候不知道某些写法,到底是数组还是字符串还是什么,这个时候,可以到网上去找一个工具,叫yaml转json,可以把yaml文件转成json形式,这样的话就能看懂到底是数组还是字符串还是嵌套对象了。比如上文中的执行命令的,我就不知道到底是个什么东西,所以我去转换了一下得到如下:
首先说一下我的helm版本:v3.3.0-rc.2,之后的版本可能会修复这个问题。
我们在使用kubenetes的时候,经常会使用强制替换命令来强制替换资源。在helm中对应的是upgrade命令。我们查看upgrade的帮助文档:helm upgrade --help 中说明我们使用upgrade的时候可以加参数,格式如下:
helm upgrade [RELEASE] [CHART] [flags]
RELEASE:本次发布的名称
CHART:chart的tgz文件或者目录
flags:要加的参数
其中有一个参数是–force,同kubenetes中的–force一样是强制替换。
在使用这个参数的过程中,如果templates目录中你定义了service文件,会报一个错误
[root@localhost helm]# helm upgrade c-api ./c-api --force
输出的错误:
Error: UPGRADE FAILED: failed to replace object: Service "c-api-svc" is invalid: spec.clusterIP: Invalid value: "": field is immutable
翻译:错误:升级失败:替换对象失败:服务“c-api-svc”无效:spec.clusterIP:无效值:“”:字段不可变
其实我的service中根本没有clusterIP这个字段。那么出现这种问题的原因是什么的。一开始在网上也查不到相关的答案。
后来经过各方查询发现一篇外国友人的朋友写到这类似的问题,其原因是在加了参数和不加的时候,helm转化成的kubenetes的命令是不一样的。helm源码如下
// if --force is applied, attempt to replace the existing resource with the new object.
if force {
obj, err = helper.Replace(target.Namespace, target.Name, true, target.Object)
if err != nil {
return errors.Wrap(err, "failed to replace object")
}
c.Log("Replaced %q with kind %s for kind %s\n", target.Name, currentObj.GetObjectKind().GroupVersionKind().Kind, kind)
} else {
// send patch to server
obj, err = helper.Patch(target.Namespace, target.Name, patchType, patch, nil)
if err != nil {
return errors.Wrapf(err, "cannot patch %q with kind %s", target.Name, kind)
}
}
分析上面的代码,Helm将把helm命令转换成kubectl命令,来向api server发起请求,当–force被设置时,就使用kubectl --force命令来替换,
如果没有,Helm将使用kubectl的patch命令请求进行升级。
我们来看看helm这样做的意义
kubectl apply -f - <<EOF
apiVersion: v1
kind: Service
metadata:
labels:
app: test-svc
name: test-svc
spec:
selector:
app: test-app
ports:
- port: 80
protocol: TCP
targetPort: 80
type: NodePort
EOF
假设有一个service定义如上(为了容易创建,直接使用的文件输入流),并且已经创建成功。
我们使用如下命令,来把这个service变成LoadBalancer类型
kubectl replace -f - <<EOF
apiVersion: v1
kind: Service
metadata:
labels:
app: test-svc
name: test-svc
spec:
selector:
app: test-app
ports:
- port: 80
protocol: TCP
targetPort: 80
type: LoadBalancer
EOF
报错如下:
The Service "test-svc" is invalid: spec.clusterIP: Invalid value: "": field is immutable
是不是出现了相同的错误,但是这里加入–force命令就能成功,如下:
kubectl replace --force -f - <<EOF
apiVersion: v1
kind: Service
metadata:
labels:
app: test-svc
name: test-svc
spec:
selector:
app: test-app
ports:
- port: 80
protocol: TCP
targetPort: 80
type: LoadBalancer
EOF
猜测还是helm内部转成kubctl命令的时候有一些选择性的问题,helm用的是patch方式来解决的。我们模拟一下patch的方式
kubectl patch svc test-svc -p '{"spec":{"type":"LoadBalancer"}}'
这个时候就会看到提示 service/test-svc patched
期待helm后续修复。
出现的原因:因为我是创建阿里云的pv和pvc的时候,直接复制了阿里云的pvc和pv的yaml文件,文件中有两个字段没有删除掉,字段如下:
apiVersion: v1
kind: PersistentVolumeClaim
metadata:
annotations:
pv.kubernetes.io/bind-completed: 'yes'
pv.kubernetes.io/bound-by-controller: 'yes'
creationTimestamp: '2020-06-11T09:30:35Z' #这个字段
finalizers:
- kubernetes.io/pvc-protection
name: oss-pvc
namespace: hhh
resourceVersion: '6388261' #这个字段
selfLink: /api/v1/namespaces/default/persistentvolumeclaims/oss-pvc2
uid: 783ggg6b-c803-46d7-b291-f697fd8d7802
spec:
...#省略
其中 resourceVersion在每次申请的时候可能会发生变化,还有creationTimestamp,最好也不要带入。helm报错如下:
Error: UPGRADE FAILED: cannot patch "oss-pvc" with kind PersistentVolumeClaim: Operation cannot be fulfilled on persistentvolumeclaims "oss-pvc": the object has been modified; please apply your changes to the latest version and try again
解决方法:把这两个字段都去掉就好了。