<?xml version="1.0" encoding="utf-8" standalone="yes" ?>
<rss version="2.0" xmlns:atom="http://www.w3.org/2005/Atom">
  <channel>
    <title>oam | 伪架构师</title>
    <link>/tags/oam/</link>
      <atom:link href="/tags/oam/index.xml" rel="self" type="application/rss+xml" />
    <description>oam</description>
    <generator>Source Themes Academic (https://sourcethemes.com/academic/)</generator><language>zh</language><lastBuildDate>Wed, 04 Dec 2019 21:20:35 +0800</lastBuildDate>
    <image>
      <url>/img/logo-wide.png</url>
      <title>oam</title>
      <link>/tags/oam/</link>
    </image>
    
    <item>
      <title>Rudr 初体验</title>
      <link>/post/rudr-at-a-glance/</link>
      <pubDate>Wed, 04 Dec 2019 21:20:35 +0800</pubDate>
      <guid>/post/rudr-at-a-glance/</guid>
      <description>

&lt;p&gt;&lt;a href=&#34;https://github.com/oam-dev/spec&#34; target=&#34;_blank&#34;&gt;OAM（开放应用模型）&lt;/a&gt; 是一次对应用运行及其支撑环境进行抽象的有意思的尝试，与之对应的控制器 &lt;a href=&#34;https://github.com/oam-dev/rudr&#34; target=&#34;_blank&#34;&gt;Rudr&lt;/a&gt; 也在同一时间诞生。有了 Rudr，OAM 就不是一个简单的标准，而是一个可以尝试落地的原型了。官方仓库提供了很好的&lt;a href=&#34;https://github.com/oam-dev/rudr/blob/master/docs/tutorials/deploy_and_update.md&#34; target=&#34;_blank&#34;&gt;入门文档&lt;/a&gt;，借此文档的帮助，能够很好的理解规范中莫名其妙的概念。这里就按照官方教程走一通，看看这种方法让应用部署运行过程发生了什么变化。&lt;/p&gt;

&lt;h2 id=&#34;安装&#34;&gt;安装&lt;/h2&gt;

&lt;p&gt;Rudr 需要 Kubernetes 1.15 以上的版本，并且使用 Helm 3 进行安装。&lt;/p&gt;

&lt;pre&gt;&lt;code class=&#34;language-shell&#34;&gt;$ git clone https://github.com/oam-dev/rudr.git
正克隆到 &#39;rudr&#39;...
remote: Enumerating objects: 49, done.
...
$ cd rudr
...
$ helm install rudr charts/rudr
...
NOTES:
Rudr is a Kubernetes controller to manage Configuration CRDs.

It has been successfully installed.
&lt;/code&gt;&lt;/pre&gt;

&lt;blockquote&gt;
&lt;p&gt;非常谦虚的一个 Note。&lt;/p&gt;
&lt;/blockquote&gt;

&lt;h2 id=&#34;部署一个-component&#34;&gt;部署一个 Component&lt;/h2&gt;

&lt;p&gt;Component 是 OAM 中的一个运行单位，代表一种运行负载，其类型可能有 Server、Job 等。下面使用示例代码创建一个 Component 对象：&lt;/p&gt;

&lt;pre&gt;&lt;code class=&#34;language-shell&#34;&gt;$ kubectl apply -f examples/helloworld-python-component.yaml
componentschematic.core.oam.dev/helloworld-python-v1 created
$ kubectl get component
NAME                   AGE
helloworld-python-v1   35s
&lt;/code&gt;&lt;/pre&gt;

&lt;p&gt;查看这个源文件，其中声明了一个 &lt;code&gt;Server&lt;/code&gt; 类型的组件，用参数的方式定义了两个环境变量 &lt;code&gt;TARGET&lt;/code&gt; 和 &lt;code&gt;PORT&lt;/code&gt;。&lt;/p&gt;

&lt;h2 id=&#34;查看-traits&#34;&gt;查看 Traits&lt;/h2&gt;

&lt;p&gt;接下来看看 Kubernetes + Rudr 为应用提供了哪些运行支撑能力：&lt;/p&gt;

&lt;pre&gt;&lt;code class=&#34;language-shell&#34;&gt;$ kubectl get traits
NAME             AGE
autoscaler       13m
empty            13m
ingress          13m
manual-scaler    13m
volume-mounter   13m
&lt;/code&gt;&lt;/pre&gt;

&lt;p&gt;熟悉 Kubernetes 的同学应该看得出，除了奇怪的 &lt;code&gt;empty&lt;/code&gt;，其他都是常见的部署元素。&lt;/p&gt;

&lt;pre&gt;&lt;code class=&#34;language-shell&#34;&gt;$ kubectl get traits autoscaler -o yaml
apiVersion: core.oam.dev/v1alpha1
kind: Trait
...
spec:
  appliesTo:
  - core.oam.dev/v1alpha1.Server
  - core.oam.dev/v1alpha1.Task
  properties: |
    {
      &amp;quot;$schema&amp;quot;: &amp;quot;http://json-schema.org/draft-
...
&lt;/code&gt;&lt;/pre&gt;

&lt;p&gt;这里可以看到，HPA 适用于 Server 和 Task 两种组件，定义了最大实例数、最小实例数以及 CPU/内存消耗阈值。&lt;/p&gt;

&lt;h2 id=&#34;运行应用&#34;&gt;运行应用&lt;/h2&gt;

&lt;p&gt;有了 Component 和 Trait，接下来可以用 &lt;code&gt;Configuration&lt;/code&gt; 启动应用了：&lt;/p&gt;

&lt;pre&gt;&lt;code class=&#34;language-shell&#34;&gt;$ kubectl apply -f examples/first-app-config.yaml
applicationconfiguration.core.oam.dev/first-app created
$ kubectl get pods
NAME                                              READY   STATUS    RESTARTS   AGE
first-app-helloworld-python-v1-855479556f-6qvk8   1/1     Running   0          38s
...
$ kubectl get ingress
NAME                                           HOSTS         ADDRESS   PORTS   AGE
first-app-helloworld-python-v1-trait-ingress   example.com             80      12m
&lt;/code&gt;&lt;/pre&gt;

&lt;p&gt;Pod 已经启动，Ingress 对象也已经建立起来，可以看看他的运行结果：&lt;/p&gt;

&lt;pre&gt;&lt;code class=&#34;language-shell&#34;&gt;$ export POD_NAME=$(kubectl get pods -l &amp;quot;oam.dev/instance-name=first-app-helloworld-python-v1,app.kubernetes.io/name=first-app&amp;quot; -o jsonpath=&amp;quot;{.items[0].metadata.name}&amp;quot;)
...
$ kubectl port-forward $POD_NAME 9999:9999 &amp;amp;
Forwarding from [::1]:9999 -&amp;gt; 9999
$ curl http://127.0.0.1:9999
Hello Rudr!
&lt;/code&gt;&lt;/pre&gt;

&lt;h2 id=&#34;修改配置&#34;&gt;修改配置&lt;/h2&gt;

&lt;p&gt;使用 &lt;code&gt;kubectl edit&lt;/code&gt; 修改上一步的配置，把 target 参数修改为 &lt;code&gt;World&lt;/code&gt;：&lt;/p&gt;

&lt;pre&gt;&lt;code class=&#34;language-yaml&#34;&gt;...
    parameterValues:
    - name: target
      value: World
...
&lt;/code&gt;&lt;/pre&gt;

&lt;p&gt;应用之后，会看到 Pod 被重建，重新执行上面的测试步骤，返回信息变成 &lt;code&gt;Hello World&lt;/code&gt;。&lt;/p&gt;

&lt;h2 id=&#34;结论&#34;&gt;结论&lt;/h2&gt;

&lt;p&gt;实际上单就这个例子来说，对比入门的 Deployment + Service + Ingress 三件套来说，复杂度并没有什么区别。然而 Component 对象的工作负载类型除了 Server 之外，还有 Job、Serverless 等复杂类型，用 Traits 可以描述多种运维能力，更不要说还有暂未浮出水面的 Application Scope 对象，猜测这个模型在公有云、多云以及混合云下，可能会有相当大的想象空间。&lt;/p&gt;
</description>
    </item>
    
    <item>
      <title>YAML 程序员眼中的 OAM</title>
      <link>/post/oam-and-lockin/</link>
      <pubDate>Mon, 21 Oct 2019 14:30:23 +0800</pubDate>
      <guid>/post/oam-and-lockin/</guid>
      <description>

&lt;p&gt;在 10.17 ，阿里云和微软联袂发布了一个有意思的新东西：OAM（开放应用模型）。这个项目要解决的问题是：用一致的、定义良好的模型来对应用进行描述。&lt;/p&gt;

&lt;p&gt;Kubernetes 达成了一个小目标：不管是什么云，上面都有 Kubernetes 的一席之地。OAM 的小目标是什么呢？&lt;/p&gt;

&lt;p&gt;OAM 用（Holy）YAML 对应用程序进行了描述，其中核心组件包含了几个：&lt;/p&gt;

&lt;ul&gt;
&lt;li&gt;Component：组件交付物&lt;/li&gt;
&lt;li&gt;Application Scope：部署目标&lt;/li&gt;
&lt;li&gt;Traits：运维能力&lt;/li&gt;
&lt;li&gt;Application Configuration：应用配置&lt;/li&gt;
&lt;/ul&gt;

&lt;p&gt;一头雾水是吧？还好每个对象都提供了代码范例，可以拿来解释。&lt;/p&gt;

&lt;h2 id=&#34;component&#34;&gt;Component&lt;/h2&gt;

&lt;blockquote&gt;
&lt;p&gt;一种类似 Pod 的东西。。。&lt;/p&gt;
&lt;/blockquote&gt;

&lt;pre&gt;&lt;code class=&#34;language-yaml&#34;&gt;apiVersion: core.oam.dev/v1alpha1
kind: ComponentSchematic
metadata:
  name: admin-backend
  annotations:
    version: v1.0.0
    description: &amp;gt;
      Sample component schematic that describes the backend for our Twitter bot.
spec:
  workloadType: core.oam.dev/v1.SingletonServer
  osType: linux
  parameters:
  ...
  - name: twitter-access-token-secret
    description: Twitter API access token secret
    type: string
    required: true
  containers:
  - name: my-twitter-bot-backend
    image:
      name: example/my-twitter-bot-backend:1.0.0
      digest: sha256:6c3c624b58dbbcd3c0dd82b4c53f04194d1247c6eebdaab7c610cf7d66709b3b
    resources:
      cpu:
        required: 1.0
      memory:
        required: 100MB
      volumes:
      - name: config
        mountPath: /var/lib/my-twitter-bot/conf
        accessMode: RW
        sharingPolicy: Exclusive
    ports:
    - name: http
      value: 8080
    env:
    ...
    - name: TWITTER_ACCESS_TOKEN_SECRET
      fromParam: &#39;twitter-access-token-secret&#39;
    livenessProbe:
      httpGet:
        port: 8080
        path: /healthz
    readinessProbe:
      httpGet:
        port: 8080
        path: /healthz
&lt;/code&gt;&lt;/pre&gt;

&lt;p&gt;很像 Kubernetes 有没有？容器、参数、资源（外部加载卷的加载方式，类似 &lt;code&gt;volumeMount&lt;/code&gt; 也定义在资源里）、端口和环境变量都是 YAML 程序员们很熟悉的东西。最值得注意的是 &lt;code&gt;workloadType&lt;/code&gt;，工作负载的类型可以分为核心和扩展两个大类，其中核心工作负载有一个明确要求：所有实现本规范的平台必须支持核心工作负载。&lt;/p&gt;

&lt;p&gt;核心工作负载有几个类型：&lt;/p&gt;

&lt;ul&gt;
&lt;li&gt;Server：可多实例运行的，对外提供服务的守护进程。&lt;/li&gt;
&lt;li&gt;Singleton Server：只能单实例运行的，对外提供服务的守护进程。&lt;/li&gt;
&lt;li&gt;Worker：能够多实例运行，不对外提供服务的守护进程。&lt;/li&gt;
&lt;li&gt;Singleton Worker：不对外提供服务，不可复制的守护进程。&lt;/li&gt;
&lt;li&gt;Task：不对外提供服务，可复制，非守护进程（一次性）。&lt;/li&gt;
&lt;li&gt;Singleton Task：不对外提供服务，不可复制，非守护进程（一次性）。&lt;/li&gt;
&lt;/ul&gt;

&lt;p&gt;另外这里还有一个字段叫 &lt;code&gt;ConfigFile&lt;/code&gt;，用于存储配置内容。&lt;/p&gt;

&lt;p&gt;在组件模型一节的尾部，给出了下面这样的例子：&lt;/p&gt;

&lt;pre&gt;&lt;code class=&#34;language-yaml&#34;&gt;apiVersion: core.oam.dev/v1alpha1
kind: ComponentSchematic
metadata:
  name: azurefunction
  annotations:
    version: v1.0.0
    description: &amp;quot;Extended workflow example&amp;quot;
spec:
  workloadType: azure.com/v1.Function
  parameters:
  - name: github-token
    description: GitHub API session key
    type: string
    required: true
  workloadSettings:
    - name: source
      value: git://git.example.com/function/myfunction.git
    - name: github_token
      fromParam: github-token
&lt;/code&gt;&lt;/pre&gt;

&lt;p&gt;这个例子展示的是扩展类型的组件：从 git 拉取代码，用于提供 Function 服务。&lt;/p&gt;

&lt;h2 id=&#34;trait&#34;&gt;Trait&lt;/h2&gt;

&lt;blockquote&gt;
&lt;p&gt;一种运行平台中，针对特定工作负载进行运维支撑的能力，例如下面例子中的手动伸缩，似乎 Service Mesh 也应该名列此列？&lt;/p&gt;
&lt;/blockquote&gt;

&lt;pre&gt;&lt;code class=&#34;language-yaml&#34;&gt;apiVersion: core.oam.dev/v1alpha1
kind: Trait
metadata:
  name: ManualScaler
  annotations:
    version: v1.0.0
    description: &amp;quot;Allow operators to manually scale a workloads that allow multiple replicas.&amp;quot;
spec:
  appliesTo:
    - core.oam.dev/v1alpha1.Server
    - core.oam.dev/v1alpha1.Worker
    - core.oam.dev/v1alpha1.Task
  properties:
    type: object
    properties: |
      {
        &amp;quot;$schema&amp;quot;: &amp;quot;http://json-schema.org/draft-07/schema#&amp;quot;,
        &amp;quot;type&amp;quot;: &amp;quot;object&amp;quot;,
        &amp;quot;required&amp;quot;: [&amp;quot;replicaCount],
        &amp;quot;properties&amp;quot;: {
          &amp;quot;replicaCount&amp;quot;: {
            &amp;quot;type&amp;quot;: &amp;quot;integer&amp;quot;,
            &amp;quot;description&amp;quot;: &amp;quot;the target number of replicas to scale a component to.&amp;quot;,
            &amp;quot;minimum&amp;quot;: 0
          }
        }
      }
&lt;/code&gt;&lt;/pre&gt;

&lt;p&gt;这里定义了一个用来做手动伸缩的 Trait，它仅适用于第一节中提到的几个可伸缩的工作负载类型。这个 Traits 仅包含一个必要字段，用于设置副本数量。&lt;/p&gt;

&lt;blockquote&gt;
&lt;p&gt;但是在 YAML 里面包 JSON 真的好吗？&lt;/p&gt;
&lt;/blockquote&gt;

&lt;h2 id=&#34;application-scopes&#34;&gt;Application Scopes&lt;/h2&gt;

&lt;blockquote&gt;
&lt;p&gt;百撕不得其解的一个概念。通过外部设施，如网络或者健康对应用范围进行划分，把应用进行聚合。
并且在 Application Configuration 中作为一个部署目标进行实例化。&lt;/p&gt;
&lt;/blockquote&gt;

&lt;pre&gt;&lt;code class=&#34;language-yaml&#34;&gt;apiVersion: core.oam.dev/v1alpha1
kind: ApplicationScope
metadata:
  name: health
  annotations:
    version: v1.0.0
    description: &amp;quot;aggregated health state for a group of components.&amp;quot;
spec:
  type: core.oam.dev/v1alpha1.HealthScope
  allowComponentOverlap: true
  parameters:
    - name: probe-method
      description: The method to probe the components, e.g. &#39;httpGet&#39;.
      type: string
      required: true
...
    - name: required-healthy-components
      description: Comma-separated list of names of the components required to be healthy for the scope to be health.
      type: []string
      required: false
&lt;/code&gt;&lt;/pre&gt;

&lt;h2 id=&#34;application-configuration&#34;&gt;Application Configuration&lt;/h2&gt;

&lt;p&gt;前面的几个概念中，描述了组件的定义、平台提供的运维能力、以及应用的部署范围，最终应用要运行起来，需要进行一个部署过程，部署过程除了把前面提到的对象组合起来之外，还需要加入一些配置内容。本对象就是用来完成这一功能的。&lt;/p&gt;

&lt;pre&gt;&lt;code class=&#34;language-yaml&#34;&gt;apiVersion: core.oam.dev/v1alpha1
kind: ApplicationConfiguration
metadata:
  name: my-vpc-network
spec:
  variables:
    - name: networkName
      value: &amp;quot;my-vpc&amp;quot;
  scopes:
    - name: network
      type: core.oam.dev/v1alpha1.Network
      properties:
        - name: network-id
          value: &amp;quot;[fromVariable(networkName)]&amp;quot;
        - name: subnet-id
          value: &amp;quot;my-subnet&amp;quot;
---
apiVersion: core.oam.dev/v1alpha1
kind: ApplicationConfiguration
metadata:
  name: custom-single-app
  annotations:
    version: v1.0.0
    description: &amp;quot;Customized version of single-app&amp;quot;
spec:
  variables:
    - name: message
      value: &amp;quot;Well hello there&amp;quot;
    - name: domainName
      value: &amp;quot;www.example.com&amp;quot;
  components:
    - componentName: frontend
      instanceName: web-front-end
      parameterValues:
        - name: message
          value: &amp;quot;[fromVariable(message)]&amp;quot;
      traits:
        - name: Ingress
          properties:
            - name: host
              value: &amp;quot;[fromVaraible(domainName)]&amp;quot;
            - name: path
              value: &amp;quot;/&amp;quot;
      applicationScopes:
        - my-vpc-network

    - componentName: backend
      instanceName: database
      applicationScopes:
        - my-vpc-network
&lt;/code&gt;&lt;/pre&gt;

&lt;p&gt;这一组文件对象完成了几个任务：&lt;/p&gt;

&lt;ul&gt;
&lt;li&gt;创建了一个网络类型的 Application Scope，&lt;code&gt;my-vpc-network&lt;/code&gt;。&lt;/li&gt;
&lt;li&gt;引用一个叫做 &lt;code&gt;frontend&lt;/code&gt; 的组件，生成 &lt;code&gt;web-front-end&lt;/code&gt; 对象，并赋予参数 &lt;code&gt;message&lt;/code&gt;。&lt;/li&gt;
&lt;li&gt;为 &lt;code&gt;web-front-end&lt;/code&gt; 提供一个 Ingress 对象。&lt;/li&gt;
&lt;li&gt;将两个实例部署在 &lt;code&gt;my-vpc-network&lt;/code&gt;。&lt;/li&gt;
&lt;/ul&gt;

&lt;h2 id=&#34;后记&#34;&gt;后记&lt;/h2&gt;

&lt;p&gt;这几个对象里，基本形成了一个从交付物到运维的标准过程和定义，并且也直接使用 Rust 实现了基于这一规范的工具。符合这个规范的应用，就能能够在支持 OAM 的平台上进行运行和运维，虽然应用自身的结构、拓扑、构建、观测还有很多元素要实现，但是这些基础元素，应该已经能够发挥很好的示范效果了。&lt;/p&gt;

&lt;p&gt;印象里 OAM 的新闻稿里有一句话，OAM 和其他应用模型是不同的，它没有供应商锁定问题，因为它是构建在 Kubernetes 的基础之上的：Kubernetes 就是在锁定横行的环境下，利用更高层次的抽象来打破旧锁定，造就新锁定的。&lt;/p&gt;
</description>
    </item>
    
  </channel>
</rss>
