Myblog

the amazing thing of think

helmfile 最佳实践指南(机翻)

本指南介绍Helmfile 用于编写高级helmfile文件所考虑的模式。它侧重于如何构建和执行helmfile文件.

缺少键和默认值

Helmfile 尽力通知用户注意潜在的错误。
helmfile如何实现的一个例子是,当你试图访问环境值中缺少的键时, helmfile会失败。
也就是说,下面的例子让 helmfile 在环境值中没有定义 eventApi.replicas 时失败。

.Values.eventApi.replicas | default 1

万一不是错误,而你又确实想允许缺失键,请使用 get 模板函数。

.Values | get “eventApi.replicas” nil

这将导致在你的模板中打印 <no value, 这可能不会导致失败。
如果你想要一个默认值,当一个缺失的键被引用时,使用默认值,如

.Values | get “eventApi.replicas” 1

现在,当环境值中没有定义eventApi.replicas时,你会得到1。

Release Template/常规目录结构

在一个涉及几十个版本的大型项目中引入 helmfile,往往会导致 files. helmfile.yaml 中出现很多重复的内容
下面的例子显示了 “namespace”、”chart”、”values “和 “secrets “中的重复。

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
releases:
# *snip*
- name: heapster
namespace: kube-system
chart: stable/heapster
version: 0.3.2
values:
- "./config/heapster/values.yaml"
- "./config/heapster/{{ .Environment.Name }}.yaml"
secrets:
- "./config/heapster/secrets.yaml"
- "./config/heapster/{{ .Environment.Name }}-secrets.yaml"
- name: kubernetes-dashboard
namespace: kube-system
chart: stable/kubernetes-dashboard
version: 0.10.0
values:
- "./config/kubernetes-dashboard/values.yaml"
- "./config/kubernetes-dashboard/{{ .Environment.Name }}.yaml"
secrets:
- "./config/kubernetes-dashboard/secrets.yaml"
- "./config/kubernetes-dashboard/{{ .Environment.Name }}-secrets.yaml"

这时Helmfile的高级功能Release Template就派上用场了。

它允许你把发布中的重复抽象掉,变成一个模板,然后通过使用YAML锚/alias来包含和执行。

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
templates:
default: &default
chart: stable/{{`{{ .Release.Name }}`}}
namespace: kube-system
# This prevents helmfile exiting when it encounters a missing file
# Valid values are "Error", "Warn", "Info", "Debug". The default is "Error"
# Use "Debug" to make missing files errors invisible at the default log level(--log-level=INFO)
missingFileHandler: Warn
values:
- config/{{`{{ .Release.Name }}`}}/values.yaml
- config/{{`{{ .Release.Name }}`}}/{{`{{ .Environment.Name }}`}}.yaml
secrets:
- config/{{`{{ .Release.Name }}`}}/secrets.yaml
- config/{{`{{ .Release.Name }}`}}/{{`{{ .Environment.Name }}`}}-secrets.yaml
releases:
- name: heapster
<<: *default
- name: kubernetes-dashboard
<<: *default

Release Templating支持以下部分的发布定义。

  • 基本字段。namenamespacechartversion
  • 布尔字段。installed, wait, tillerless, verify等字段,并附加文字。

仅为模板设计的字段:installedTemplate, waitTemplate, tillerlessTemplate, verifyTemplate

1
2
3
4
# ...
installedTemplate: '{{`{{ eq .Release.Namespace "kube-system" }}`}}'
waitTemplate: '{{`{{ eq .Release.Labels.tag "safe" | not }}`}}'
# ...
  • set块值

    1
    2
    3
    4
    5
    # ...
    setTemplate:
    - name: '{{`{{ .Release.Name }}`}}'
    values: '{{`{{ .Release.Namespace }}`}}'
    # ...
  • “值”和”机密”文件路径

    1
    2
    3
    4
    5
    6
    # ...
    valuesTemplate:
    - config/{{`{{ .Release.Name }}`}}/values.yaml
    secrets:
    - config/{{`{{ .Release.Name }}`}}/secrets.yaml
    # ...
  • 内联”value”映射:

    1
    2
    3
    4
    5
    # ...
    valuesTemplate:
    - image:
    tag: `{{ .Release.Labels.tag }}`
    # ...

    查看 issue 428 了解更多关于这应该如何工作的背景。

分层发布值

请注意,不可能对 “values “部分进行分层。如果 “values “是在发布版和发布版模板中定义的,则只考虑发布版中定义的 “values”。这同样适用于 “secrets “和 “set”。

状态文件分层

如果你要分层模板,请看分层状态模板文件

你可能偶尔会有很多helmfile,这些helmfile共享一些共同的部分,比如使用哪个仓库,默认要捆绑哪个版本。

使用Layering将共同的部分提取到一个专门的库 helmfile中,这样每个头盔文件就变成了DRY。

假设你的’helmfile.yaml’长这样:

1
2
3
4
5
6
7
bases:
- environments.yaml
releases:
- name: metricbeat
chart: stable/metricbeat
- name: myapp
chart: mychart

environments.yaml则包含了众所周知的环境。

1
2
3
environments:
development:
production:

在运行时,你的 “helmfile.yaml “中的 “bases “将被评估以产生。

1
2
3
4
5
6
7
8
9
10
11
12
---
# environments.yaml
environments:
development:
production:
---
# helmfile.yaml
releases:
- name: myapp
chart: mychart
- name: metricbeat
chart: stable/metricbeat

最后将产生的YAML文档按照出现的顺序进行合并。
这样你的helmfile.yaml就变成了:

1
2
3
4
5
6
7
8
environments:
development:
production:
releases:
- name: metricbeat
chart: stable/metricbeat
- name: myapp
chart: mychart

Great!

现在,对你的每个 “helmfile.yaml “重复以上步骤,这样你所有的helmfiles就会变成DRY。

合并层中数组

Helmfile不会跨层合并数组。也就是说,下面的例子并不能像你想象的那样工作。

1
2
3
4
5
6
7
releases:
- name: metricbeat
chart: stable/metricbeat
---
releases:
- name: myapp
chart: mychart

Helmfile用最新的层覆盖了releases数组,所以产生的状态文件将:

1
2
3
4
releases:
# metricbeat release disappeared! but that's how helmfile works
- name: myapp
chart: mychart

一个变通的办法是将状态文件作为一个go模板,并使用readFile模板函数将你的状态文件的公共部分以纯文本的形式导入。

common.yaml:

1
2
3
4
templates:
metricbeat: &metricbeat
name: metricbeat
chart: stable/metricbeat

helmfile.yaml:

1
2
3
4
5
{{ readFile "common.yaml" }}
releases:
- <<: *metricbeat
- name: myapp
chart: mychart

分层状态模板文件

你需要让你的状态文件更DRY吗?

发现分层状态文件对你来说还不够?

Helmfile支持一个高级功能,可以让你组成状态 “模板 “文件来生成最终要处理的状态。

在下面的例子helmfile.yaml.gotmpl中,文件中每一个----分隔的部分都是一个go模板。

helmfile.yaml.gotmpl:

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
# Part 1: Reused Enviroment Values
bases:
- myenv.yaml
---
# Part 2: Reused Defaults
bases:
- mydefaults.yaml
---
# Part 3: Dynamic Releases
releases:
- name: test1
chart: mychart-{{ .Values.myname }}
values:
replicaCount: 1
image:
repository: "nginx"
tag: "latest"

假设第一部分加载的myenv.yamltest.env.yaml是这样的。

myenv.yaml:

1
2
3
4
environments:
test:
values:
- test.env.yaml

test.env.yaml:

1
2
3
4
kubeContext: test
wait: false
cvOnly: false
myname: "dog"

其中第二部分加载的gotmpl文件是这样的:

mydefaults.yaml.gotmpl:

1
2
3
4
5
6
7
8
9
10
11
12
helmDefaults:
tillerNamespace: kube-system
kubeContext: {{ .Values.kubeContext }}
verify: false
{{ if .Values.wait }}
wait: true
{{ else }}
wait: false
{{ end }}
timeout: 600
recreatePods: false
force: true

每个go模板都是在.Values从前一部分继承的上下文中呈现的。

所以在mydefaults.yaml.gotmpl中,.Values.kubeContext.Values.wait都是有效的,因为它们确实存在于你的helmfile.yaml.gotmpl的前一部分(=第一部分)继承的环境值中,因此模板被渲染到。

1
2
3
4
5
6
7
8
helmDefaults:
tillerNamespace: kube-system
kubeContext: test
verify: false
wait: false
timeout: 600
recreatePods: false
force: true

同样,顶层helmfile.yaml.gotmpl的第三部分.Values.myname也是有效的,因为它包含在从前面部分继承的环境值中:

1
2
3
4
5
6
7
8
9
# Part 3: Dynamic Releases
releases:
- name: test1
chart: mychart-{{ .Values.myname }}
values:
replicaCount: 1
image:
repository: "nginx"
tag: "latest"

因此呈现:

1
2
3
4
5
6
7
8
9
# Part 3: Dynamic Releases
releases:
- name: test1
chart: mychart-dog
values:
replicaCount: 1
image:
repository: "nginx"
tag: "latest"

helm-常用命令

helm 基本概念

helm 是 k8s的包管理工具。包管理方面有几个基本概念对应于helm是这样的:

    • 被称为 hub, 类似于各个镜像之间的搜索。
    • 本地用的被称为 Repository,就是 k8s的数据库
    • 被称为chart, 可以是工具,应用,服务。
  • 实例
    • 被称为instance,chart每在集群上安装一次就会创建一个实例。

一言以蔽之。

Helm installs charts into Kubernetes, creating a new release for each installation. And to find new charts, you can search Helm chart repositories.

常用命令

  • helm search

    • helm search hub chartName hub上搜索名为chartName的chart 并列出
    • helm search repo chartName 本地用的repo上搜索chartName并列出
  • helm install instanceName chartName 安装包

  • helm install foo chartName 安装本地包

  • helm update -f instanceName chartName 更新包

  • helm rollback chartName version 回滚到某个版本

  • helm unstall instanceName 删除包

  • helm list 查看所有包

  • helm show values 查看所有配置

程序编译与链接

整个流程

  • 预编译
  • 编译
  • 汇编
  • 链接

预处理

预编译过程主要处理那些源文件中的以“#”开始的预编译指令,主要处理规则有:

  1. 将所有的“#define”删除,并展开所用的宏定义
  2. 处理所有条件预编译指令,比如“#if”、“#ifdef”、 “#elif”、“#endif”
  3. 处理“#include”预编译指令,将被包含的文件插入到该编译指令的位置,注:此过程是递归进行的
  4. 删除所有注释
  5. 添加行号和文件名标识,以便于编译时编译器产生调试用的行号信息以及用于编译时产生编译错误或警告时可显示行号
  6. 保留所有的#pragma编译器指令。

编译

编译过程就是把预处理完的文件进行一系列的词法分析、语法分析、语义分析及优化后生成相应的汇编代码文件。这个过程是整个程序构建的核心部分。

汇编

汇编器是将汇编代码转化成机器可以执行的指令,每一条汇编语句几乎都是一条机器指令。经过编译、链接、汇编输出的文件成为.o目标文件(Object File)

链接

链接的主要内容就是把各个模块之间相互引用的部分处理好,使各个模块可以正确的拼接。
链接的主要过程包块 地址和空间的分配(Address and Storage Allocation)、符号决议(Symbol Resolution)和重定位(Relocation)等步骤。

python Jax

jax

jax 是Google 开源的非官方机器学习框架,个人感觉 清爽高效。而且相对于tensorflow,pytorch 围绕张量展开计算。还是喜欢基于矩阵进行的计算。另外一点就是Jax 是jax.numpy 和 jax.scipy 是用TPU加速的。对神经网络芯片软加速有一定的借鉴意义。
内有两大神器

  • autograd /pytorch 倒是也有
  • xla /是一种针对特定领域的线性代数编译器
    另一点就是
  • Jax 重写了random算法。这个和其他的都不太一样。

Jax的生态。从Awesome Jax 翻译过来包括以下这些。但我都没用过
Flax - 一个灵活的库,拥有所有JAX NN库中最大的用户群。
Haiku–专注于简单,由DeepMind的Sonnet作者创建。
Objax - 具有类似于PyTorch的面向对象设计。
Elegy–实现了Keras API的一些改进。
RLax - 实现强化学习代理的库。
Trax–一个 “考虑使用电池 “的深度学习库,专注于为常见工作负载提供解决方案。应该是偏节能。
Jraph - 一个轻量级的图神经网络库。
NumPyro - 基于Pyro库的概率编程。
Chex - 编写和测试可靠的JAX代码的实用工具。
Optax - 一个梯度处理和优化库。
JAX, M.D. - 加速的微分分子动力学。
Coax - 将RL论文转化为代码,简单的方法。
SymJAX - 符号CPU/GPU/TPU编程。
mcx - 为执行推理表达和编译概率程序。
Parallax - JAX的不可变torch 模块原型/应该算 能TPU加速的torch。
FedJAX - JAX中的联合学习,建立在Optax和Haiku之上。
jax-unirep - 为蛋白质机器学习应用实现UniRep模型的库。
jax-flows - 在JAX中规范化流。
sklearn-jax-kernels - 基于Jax 的scikit-learn kernel.
jax-cosmo - 一个可区分的宇宙学库。
efax - JAX中的指数族。
mpi4jax - 将MPI操作与CPU和GPU上的Jax代码相结合。