kubetpl - kubernetes 模板管理工具

Helm、Kustomize、Kubetpl

  • 本人实际没有使用过 Helm 和 Kustomiz 这两款工具,以下的对比,仅个人观点,仅供参考;如果有说的不对的地方,还望指点

Helm

  • 在有网络的情况下
    • Helm 可以很好的进行产品的迭代升级,只需要配置好 repo 仓库,拉取相应版本的 chart 包,修改对应的 values.yaml 文件就可以完成
      • 对于需要快速部署一些主流的中间件或者服务的时候,可以不需要去考虑自己需要准备那些对象(deployment、service、configmap等等),因为仓库里面都有现成的,不需要自己造轮子,拿来就可以用
  • 在没有网络的情况下
    • 比如一些 saas 类型的产品交付公司,在一些银行、证券类的客户现场,大多数的生产环境是不通外网的,在这些苛刻条件下,如果使用 Helm 就会需要涉及 Helm 的私仓,相对于交付来说,架构会过于庞大且麻烦

Kustomize

  • Helm 对于服务的定制仅限于预置变量,那么如果需要更多更灵活的的 YAML 定制就需要用到 Kustomize
  • Kustomize 是一套采用合并思想,对 Kubernetes 原生配置进行管理的工具,使用无模板的方案定义应用配置
    • 允许用户使用一系列的描述文件为基础,然后通过 overlay 的方式生成最终部署应用所需的描述文件

Kubetpl

  • 有点类似于 Helm 的 values.yaml 的方式配置相应的变量,通过预先配置好的 yaml 文件模板,带入变量后生成新的 yaml 文件
  • 可以定制化配置不同场景的模板,不过模板的管理会相对麻烦很多
  • 比较轻量化,不需要任何服务器组件,只是单纯的配置和管理 yaml 文件

安装 Kubetpl

curl -sSL https://github.com/shyiko/kubetpl/releases/download/0.9.0/kubetpl-0.9.0-$(
    bash -c '[[ $OSTYPE == darwin* ]] && echo darwin || echo linux'
  )-amd64 -o kubetpl && chmod a+x kubetpl && sudo mv kubetpl /usr/local/bin/

Kubetpl 命令参数

参数选项

  • completion - 命令行参数自动补齐
  • help - 命令帮助
  • render - 渲染模板
completion - 参数自动补齐
  • 可选参数:bashzsh
# bash
source <(kubetpl completion bash)

# zsh
source <(kubetpl completion zsh)
render - 渲染模板
参数解释
--allow-fs-access--chroot=<directory containing template> 的 缩写
-c, --chroot stringkubetpl/data-from-file 允许读取的文件的路径,--chroot 以外的文件都会被拒绝访问
在模板文件中可以写好路径,使用 --allow-fs-access 参数也可以实现
-z, --freeze
--freeze-list stringSlice
--freeze-ref stringArray
--ignore-unset
冻结 ConfigMap/Secret
<kind>/<name> 的方式冻结,例如(ConfigMap/foo, Secret/bar)
不应包含在输出中的外部 ConfigMap/Secret,但需要对其进行 --freeze 的引用
如果未设置,则保留 $VAR/${VAR}(例如,"echo 'kind:$A$B'|kubetpl r --s A=X --syntax=$ --ignore-unset" 输出:"kind:X$B")`
-i, --input stringArray指定配置文件:*.{env,yml,yaml,json}
-o, --output string指定输出的文件名称
-s, --set stringArray<var>=<value> 的形式申明变量
如果 --input 有配置则以 --input 优先
变量少的情况下,可以不写 --input,直接使用 --set 申明
-x, --syntax string定义模板风格
$,go-template,template-kind - 三个可选项

关于模板风格:$,go-template,template-kind ,主要区别在于变量引用的方式不同

  • $ - shell 的风格
    • $NAME
  • go-template - go 语言 template 库的风格
    • {{ .VAR }} - 获取变量名称为 VAR 的变量值
    • {{ if isset "VAR" }} ... {{ end }} - 当定义了 VAR 变量的时候才会在 }} ... {{ 中间展示变量值
    • {{ get "VAR" "default" }} - 获取 VAR 的值,如果未设置,则返回 "default"
    • {{ .VAR | quote }} - 引用 VAR 值
    • {{ .VAR | indent 4 }} - VAR 的缩进值(带 4 个空格)
    • {{ .VAR | b64enc }} - VAR 值以 base64 编码展示
  • template-kind - 没太看懂....

go-template 语法

  • 本人没有接触过 go 语言,临时找了一些资料来学习一些简单的使用
  • go 语言的变量好像是不支持 - 出现在变量名称内的,go 语言使用的是驼峰命名,不然可能会有这样的报错:
    • template: nginx-template.yaml:3: unexpected bad character U+002D '-' in range

注释

{{/* 注释 */}}

引用变量

  • 输出 hostAlias 变量的值
{{ .hostAlias }}
  • hostAlias 是匿名字段时,可以访问其内部字段或方法
{{ .hostAlias.ip }}
  • 如果需要引用外部变量,需要在前面加上 $ 符号
{{ $.hostAlias }} 

在 template 中定义变量

  • 变量名称前面需要带上 $ 符号
  • 使用 := 来对变量赋值
{{ $x := "hello" }}
  • 定义变量的值引用其他变量的值
{{ $x := .hostAlias }}

条件判断

  • if 后面可以是一个条件表达式(包括管道函数表达式。pipeline 即管道)
  • 也可以是一个字符串变量布尔值变量
    • 当为字符串变量时,如为空字符串则判断为 false,否则判断为 true
{{ if .hostAlias }}
- ip: {{ .ip }}
  hostnames: {{ .hostnames }}
{{ end }}

遍历

  • 普通用法,当变量值存在时才会有后面的内容输出
{{ range $.hostAliases }}
- ip: {{ .ip }}
  hostnames: {{ .hostnames }}
{{ end }}
  • 另一种用法
{{ range $k,$v := .labels }}
{{ $k }}: {{ $v }}
{{ end }}

开始使用

简单使用

准备一个 yaml 模板
  • 这里直接从 github 上面复制过来用了,以下所有的 yaml 文件只是用来模拟 kubetpl 生成 yaml 文件使用的,不能被直接使用的
  • # kubetpl:syntax:go-template
    • 定义模板风格,如果不在模板文件内定义,则需要通过 --syntax 的方式申明,否则会有类似如下报错
      • does not appear to be a valid YAML (yaml: line 3: did not find expected key). Did you forget to specify --syntax=<$|go-template|template-kind> / add "# kubetpl:syntax:<$|go-template|template-kind>"?
# kubetpl:syntax:go-template

apiVersion: v1
kind: Service
metadata:
  name: {{ .NAME }}-service
spec:
  selector:
    app: {{ .NAME }}
  ports:
  - protocol: TCP
    port: 80
---
apiVersion: apps/v1beta1
kind: Deployment
metadata:
  name: {{ .NAME }}-deployment
spec:
  replicas: {{ .REPLICAS }}
  template: 
    metadata:
      labels:
        app: {{ .NAME }}
    spec:
      containers:
      - name: nginx
        image: nginx:1.7.9
        ports:
        - containerPort: 80
准备变量文件
  • 支持的格式

    • *.env - <var>=<value>
    • yaml/json 文件

    *.env 的方式

cat << EOF > valus.env
NAME=sample-app
REPLICAS=2
EOF

yaml 文件 的方式

cat << EOF > env.yaml
NAME: my-nginx
REPLICAS: 3
EOF
生成新的 yaml 文件
  • 两个变量文件定义的变量值是有差异的,这个单纯就是用来比较使用的,只是选择哪种变量文件,全看各自的选择
# 使用 valus.env
kubetpl render nginx-template.yaml -i valus.env -o nginx-env.yaml

# 使用 env.yaml
kubetpl render nginx-template.yaml -i env.yaml -o nginx-yaml.yaml

稍微复杂一点的场景

  • 因为 kubetpl 是通过 -i 的方式引入的变量,所以下面的变量引用都需要加上 $ 符号表示外部引入变量,才能正常识别,不然会有类似如下的报错:
    • template: nginx-template.yaml:9:23: executing "nginx-template.yaml" at <.static.namespace>: map has no entry for key "static"
准备一个 yaml 模板
# kubetpl:syntax:go-template

{{ range $getName := .staticInfo }}
---
apiVersion: v1
kind: Service
metadata:
  name: {{ $getName.name }}-svc
  namespace: {{ $.static.namespace }}
spec:
  selector:
    app: {{ $getName.name }}
  ports:
  - protocol: TCP
    port: {{ $getName.port }}
---
apiVersion: apps/v1beta1
kind: Deployment
metadata:
  name: {{ $getName.name }}
  namespace: {{ $.static.namespace }}
spec:
  replicas: {{ $.static.replicas }}
  template:
    metadata:
      labels:
        app: {{ $getName.name }}
    spec:
      containers:
      - name: {{ $getName.name }}
        image: {{ $.global.Image }}
        imagePullPolicy: {{ $.global.ImagePull }}
        ports:
        - containerPort: 80
{{ end }}
准备变量文件
global:
  Image: nginx:1.16
  ImagePull: IfNotPresent
static:
  namespace: web-static
  replicas: 3
staticInfo:
  - name: app-static
    port: 80
  - name: backend-static
    port: 8080
生成新的 yaml 文件
kubetpl render nginx-template.yaml -i env.yaml -o nginx.yaml
生成后的 yaml 文件
---
apiVersion: v1
kind: Service
metadata:
  name: app-static-svc
  namespace: web-static
spec:
  ports:
  - port: 80
    protocol: TCP
  selector:
    app: app-static
---
apiVersion: apps/v1beta1
kind: Deployment
metadata:
  name: app-static
  namespace: web-static
spec:
  replicas: 3
  template:
    metadata:
      labels:
        app: app-static
    spec:
      containers:
      - image: nginx:1.16
        imagePullPolicy: IfNotPresent
        name: app-static
        ports:
        - containerPort: 80
---
apiVersion: v1
kind: Service
metadata:
  name: backend-static-svc
  namespace: web-static
spec:
  ports:
  - port: 8080
    protocol: TCP
  selector:
    app: backend-static
---
apiVersion: apps/v1beta1
kind: Deployment
metadata:
  name: backend-static
  namespace: web-static
spec:
  replicas: 3
  template:
    metadata:
      labels:
        app: backend-static
    spec:
      containers:
      - image: nginx:1.16
        imagePullPolicy: IfNotPresent
        name: backend-static
        ports:
        - containerPort: 80

kubetpl/data-from-file

  • 当我们需要配置 configmap 的时候,可以通过文件带入的形式来配置 yaml 文件,这样可以单独维护 configmap 给所有的 yaml 文件来使用,对于维护来说,能减轻不少的成本
准备一个 yaml 模板
# kubetpl:syntax:go-template

---
apiVersion: v1
kind: ConfigMap
kubetpl/data-from-file:
  - ./nginx.conf

metadata:
  name: {{ $.configmap.name }}
  namespace: {{ $.static.namespace }}
data:

{{ range $getName := .staticInfo }}
---
apiVersion: v1
kind: Service
metadata:
  name: {{ $getName.name }}-svc
  namespace: {{ $.static.namespace }}
spec:
  selector:
    app: {{ $getName.name }}
  ports:
  - protocol: TCP
    port: {{ $getName.port }}
---
apiVersion: apps/v1beta1
kind: Deployment
metadata:
  name: {{ $getName.name }}
  namespace: {{ $.static.namespace }}
spec:
  replicas: {{ $.static.replicas }}
  template:
    metadata:
      labels:
        app: {{ $getName.name }}
    spec:
      containers:
      - name: {{ $getName.name }}
        image: {{ $.global.Image }}
        imagePullPolicy: {{ $.global.ImagePull }}
        ports:
        - containerPort: 80
        volumeMounts:
        - name: nginx-conf
          mountPath: /workspace/nginx/conf
    volumes:
    - name: nginx-conf
      configMap:
        name: {{ $.configmap.name }}
{{ end }}
准备变量文件
  • 对比前面的,增加了一个 configmap
global:
  Image: nginx:1.16
  ImagePull: IfNotPresent
static:
  namespace: web-static
  replicas: 3
staticInfo:
  - name: app-static
    port: 80
  - name: backend-static
    port: 8080
configmap:
  name: static-cm
准备 file 文件
  • 命名为 nginx.conf
user root;
worker_processes 4;
error_log  logs/nginx_error.log  warn;
pid  logs/nginx.pid;
worker_rlimit_nofile 51200;
events {
  use epoll;
  worker_connections 51200;
  multi_accept on;
}

http {
  include       mime.types;
  default_type  application/octet-stream;

  server_names_hash_bucket_size 128;
  client_header_buffer_size 256k;
  large_client_header_buffers 16 256k;
  client_max_body_size 1m;

  keepalive_timeout 0;
  client_body_timeout 10;
  client_header_timeout 10;
  send_timeout 5;

  sendfile on;
  tcp_nopush  on;
  tcp_nodelay on;

  gzip on;
  gzip_min_length  1k;
  gzip_buffers     4 16k;
  gzip_http_version 1.0;
  gzip_comp_level 5;
  gzip_disable "MSIE [1-6].";
  gzip_types text/plain application/x-javascript text/css text/javascript application/x-httpd-php image/jpeg image/gif image/png application/json;
  gzip_vary on;

  ssi on;
  ssi_silent_errors on;
  ssi_types text/shtml;
  proxy_temp_path proxy_temp 1 2;
  client_body_temp_path client_body_temp 1 2;
  fastcgi_temp_path fastcgi_temp 1 2;
  uwsgi_temp_path uwsgi_temp 1 2;
  scgi_temp_path scgi_temp 1 2;
  set_real_ip_from 0.0.0.0/0;
  real_ip_header  X-Forwarded-For;
  real_ip_recursive   on;
  underscores_in_headers on;

  resolver kube-dns.kube-system valid=5s;
  resolver_timeout 5s;
  access_log off;

  server {
      listen       8080;
      server_name  test.com;
      set $proto_host "${http_x_forwarded_proto}_${host}";

      proxy_set_header Host $host;
      proxy_set_header X-Real-IP $remote_addr;
      proxy_set_header X-Forwarded-For $proxy_add_x_forwarded_for;
      proxy_set_header X-Forwarded-Proto $http_x_forwarded_proto;

      location /static/ {
        location ~* \.(gif|jpg|jpeg|png|bmp|swf|ico)$ {
          expires      30d;
        }
        expires 1h;
      }
  }
}
生成新的 yaml 文件
  • 使用 kubetpl/data-from-file 的话,需要加上 --allow-fs-access 参数,不然会出现类似如下的报错:
    • nginx-template.yaml: access denied: nginx.conf (use --allow-fs-access and/or -c/--chroot=<root dir, e.g. '.'> to allow)
kubetpl render --allow-fs-access nginx-template.yaml -i env.yaml -o nginx.yaml
生成后的 yaml 文件
---
apiVersion: v1
data:
  nginx.conf: |
    user root;
    worker_processes 4;
    error_log  logs/nginx_error.log  warn;
    pid  logs/nginx.pid;
    worker_rlimit_nofile 51200;
    events {
      use epoll;
      worker_connections 51200;
      multi_accept on;
    }

    http {
      include       mime.types;
      default_type  application/octet-stream;

      server_names_hash_bucket_size 128;
      client_header_buffer_size 256k;
      large_client_header_buffers 16 256k;
      client_max_body_size 1m;

      keepalive_timeout 0;
      client_body_timeout 10;
      client_header_timeout 10;
      send_timeout 5;

      sendfile on;
      tcp_nopush  on;
      tcp_nodelay on;

      gzip on;
      gzip_min_length  1k;
      gzip_buffers     4 16k;
      gzip_http_version 1.0;
      gzip_comp_level 5;
      gzip_disable "MSIE [1-6].";
      gzip_types text/plain application/x-javascript text/css text/javascript application/x-httpd-php image/jpeg image/gif image/png application/json;
      gzip_vary on;

      ssi on;
      ssi_silent_errors on;
      ssi_types text/shtml;
      proxy_temp_path proxy_temp 1 2;
      client_body_temp_path client_body_temp 1 2;
      fastcgi_temp_path fastcgi_temp 1 2;
      uwsgi_temp_path uwsgi_temp 1 2;
      scgi_temp_path scgi_temp 1 2;
      set_real_ip_from 0.0.0.0/0;
      real_ip_header  X-Forwarded-For;
      real_ip_recursive   on;
      underscores_in_headers on;

      resolver kube-dns.kube-system valid=5s;
      resolver_timeout 5s;
      access_log off;

      server {
          listen       8080;
          server_name  test.com;
          set $proto_host "${http_x_forwarded_proto}_${host}";

          proxy_set_header Host $host;
          proxy_set_header X-Real-IP $remote_addr;
          proxy_set_header X-Forwarded-For $proxy_add_x_forwarded_for;
          proxy_set_header X-Forwarded-Proto $http_x_forwarded_proto;

          location /static/ {
            location ~* \.(gif|jpg|jpeg|png|bmp|swf|ico)$ {
              expires      30d;
            }
            expires 1h;
          }
      }
    }
kind: ConfigMap
metadata:
  name: static-cm
  namespace: web-static
---
apiVersion: v1
kind: Service
metadata:
  name: app-static-svc
  namespace: web-static
spec:
  ports:
  - port: 80
    protocol: TCP
  selector:
    app: app-static
---
apiVersion: apps/v1beta1
kind: Deployment
metadata:
  name: app-static
  namespace: web-static
spec:
  replicas: 3
  template:
    metadata:
      labels:
        app: app-static
    spec:
      containers:
      - image: nginx:1.16
        imagePullPolicy: IfNotPresent
        name: app-static
        ports:
        - containerPort: 80
        volumeMounts:
        - mountPath: /workspace/nginx/conf
          name: nginx-conf
    volumes:
    - configMap:
        name: static-cm
      name: nginx-conf
---
apiVersion: v1
kind: Service
metadata:
  name: backend-static-svc
  namespace: web-static
spec:
  ports:
  - port: 8080
    protocol: TCP
  selector:
    app: backend-static
---
apiVersion: apps/v1beta1
kind: Deployment
metadata:
  name: backend-static
  namespace: web-static
spec:
  replicas: 3
  template:
    metadata:
      labels:
        app: backend-static
    spec:
      containers:
      - image: nginx:1.16
        imagePullPolicy: IfNotPresent
        name: backend-static
        ports:
        - containerPort: 80
        volumeMounts:
        - mountPath: /workspace/nginx/conf
          name: nginx-conf
    volumes:
    - configMap:
        name: static-cm
      name: nginx-conf

最后推荐几在找资料的时候看到的文章和大家一起学习

  • 3
    点赞
  • 3
    收藏
    觉得还不错? 一键收藏
  • 1
    评论

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论 1
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值