helm3进阶使用和出错排查

一些升级用法

定义复杂类型模板

我们上文中有讲过怎么遍历对象和数组,但是没有具体的讲怎么使用,现在教程来了。

引用多级对象

#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转json

对yaml不熟悉的时候不知道某些写法,到底是数组还是字符串还是什么,这个时候,可以到网上去找一个工具,叫yaml转json,可以把yaml文件转成json形式,这样的话就能看懂到底是数组还是字符串还是嵌套对象了。比如上文中的执行命令的,我就不知道到底是个什么东西,所以我去转换了一下得到如下:

错误排查

upgrade 更新资源失败

首先说一下我的helm版本:v3.3.0-rc.2,之后的版本可能会修复这个问题。

强制升级service提示spec.clusterIP: Invalid value: “”: field is immutable

我们在使用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替换失败,说是资源已经改变

出现的原因:因为我是创建阿里云的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

解决方法:把这两个字段都去掉就好了。

你可能感兴趣的:(helm,k8s,helm3的pv和pvc错误,helm3在upload报错,helm3中遍历数组和对象,helm3中的map对象,helm3的range用法)